Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
ea77fb113d | 1 month ago |
@ -1,3 +0,0 @@
|
||||
{
|
||||
"remote.autoForwardPortsFallback": 0
|
||||
}
|
||||
@ -1,21 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* 数据库配置文件
|
||||
* 使用环境变量或默认配置
|
||||
*/
|
||||
|
||||
return [
|
||||
'host' => getenv('DB_HOST') ?: '127.0.0.1', // 使用127.0.0.1连接映射端口
|
||||
'port' => getenv('DB_PORT') ?: '3308', // Docker映射端口
|
||||
'database' => getenv('DB_DATABASE') ?: 'mail_server',
|
||||
'username' => getenv('DB_USERNAME') ?: 'mail_user',
|
||||
'password' => getenv('DB_PASSWORD') ?: 'user123',
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'options' => [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
|
||||
]
|
||||
];
|
||||
<?php
|
||||
/**
|
||||
* 数据库配置文件
|
||||
* 使用环境变量或默认配置
|
||||
*/
|
||||
|
||||
return [
|
||||
'host' => getenv('DB_HOST') ?: '127.0.0.1', // 使用127.0.0.1连接映射端口
|
||||
'port' => getenv('DB_PORT') ?: '3308', // Docker映射端口
|
||||
'database' => getenv('DB_DATABASE') ?: 'mail_server',
|
||||
'username' => getenv('DB_USERNAME') ?: 'mail_user',
|
||||
'password' => getenv('DB_PASSWORD') ?: 'user123',
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'options' => [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
|
||||
]
|
||||
];
|
||||
|
||||
@ -1,44 +1,44 @@
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: mail-mysql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root123
|
||||
MYSQL_DATABASE: mail_server
|
||||
MYSQL_USER: mail_user
|
||||
MYSQL_PASSWORD: user123
|
||||
ports:
|
||||
- "3308:3306"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./scripts/create_all_tables.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
command:
|
||||
--character-set-server=utf8mb4
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
--default-authentication-plugin=mysql_native_password
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot123"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
container_name: mail-phpmyadmin
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PMA_HOST: mysql
|
||||
PMA_PORT: 3306
|
||||
PMA_USER: root
|
||||
PMA_PASSWORD: root123
|
||||
UPLOAD_LIMIT: 64M
|
||||
ports:
|
||||
- "8088:80"
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: mail-mysql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root123
|
||||
MYSQL_DATABASE: mail_server
|
||||
MYSQL_USER: mail_user
|
||||
MYSQL_PASSWORD: user123
|
||||
ports:
|
||||
- "3308:3306"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./scripts/create_all_tables.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
command:
|
||||
--character-set-server=utf8mb4
|
||||
--collation-server=utf8mb4_unicode_ci
|
||||
--default-authentication-plugin=mysql_native_password
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot123"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
container_name: mail-phpmyadmin
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PMA_HOST: mysql
|
||||
PMA_PORT: 3306
|
||||
PMA_USER: root
|
||||
PMA_PASSWORD: root123
|
||||
UPLOAD_LIMIT: 64M
|
||||
ports:
|
||||
- "8088:80"
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
mysql-data:
|
||||
@ -1,20 +0,0 @@
|
||||
启动最简POP3邮件服务器
|
||||
==============================
|
||||
|
||||
POP3服务器启动在 0.0.0.0:1100
|
||||
按 Ctrl+C 停止
|
||||
|
||||
数据库连接成功
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
服务器: +OK POP3 Simple Server Ready
|
||||
@ -1,7 +0,0 @@
|
||||
启动最简SMTP邮件服务器
|
||||
==============================
|
||||
|
||||
SMTP服务器启动在 0.0.0.0:25
|
||||
按 Ctrl+C 停止
|
||||
|
||||
数据库连接成功
|
||||
@ -1,194 +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="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; ?>
|
||||
|
||||
<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>
|
||||
|
||||
<?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>
|
||||
|
||||
|
||||
@ -1,238 +1,240 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/../src/storage/Database.php';
|
||||
require_once __DIR__ . '/../src/storage/EmailRepository.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$emailRepo = new EmailRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理删除邮件
|
||||
if (isset($_GET['delete'])) {
|
||||
$emailId = (int)$_GET['delete'];
|
||||
if ($emailRepo->delete($emailId)) {
|
||||
$message = "邮件删除成功";
|
||||
} else {
|
||||
$error = "删除失败";
|
||||
}
|
||||
}
|
||||
|
||||
// 处理标记已读
|
||||
if (isset($_GET['mark_read'])) {
|
||||
$emailId = (int)$_GET['mark_read'];
|
||||
if ($emailRepo->markAsRead($emailId)) {
|
||||
$message = "邮件已标记为已读";
|
||||
}
|
||||
}
|
||||
|
||||
// 获取邮件列表
|
||||
$isAdmin = $_SESSION['is_admin'] ?? false;
|
||||
$userId = $_SESSION['user_id'];
|
||||
|
||||
// 分页参数
|
||||
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
||||
$perPage = 20;
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
// 获取邮件
|
||||
if ($isAdmin) {
|
||||
$emails = $emailRepo->getAll($perPage, $offset);
|
||||
$totalEmails = $emailRepo->getCount();
|
||||
} else {
|
||||
$emails = $emailRepo->getInbox($userId, $perPage, $offset);
|
||||
$totalEmails = $emailRepo->getCount($userId);
|
||||
}
|
||||
|
||||
$totalPages = ceil($totalEmails / $perPage);
|
||||
?>
|
||||
<!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; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
th { background: #f8f9fa; font-weight: 600; }
|
||||
tr:hover { background: #f8f9fa; }
|
||||
.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-small { padding: 4px 8px; font-size: 12px; }
|
||||
.badge { padding: 4px 8px; border-radius: 3px; font-size: 12px; font-weight: 500; }
|
||||
.badge-read { background: #6c757d; color: white; }
|
||||
.badge-unread { background: #007bff; color: white; }
|
||||
.email-unread { font-weight: bold; }
|
||||
.pagination { margin-top: 20px; text-align: center; }
|
||||
.pagination a { display: inline-block; padding: 8px 12px; margin: 0 4px; text-decoration: none; border: 1px solid #ddd; border-radius: 4px; }
|
||||
.pagination a:hover { background: #f8f9fa; }
|
||||
.pagination .current { background: #007bff; color: white; border-color: #007bff; }
|
||||
.email-preview { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); overflow: auto; }
|
||||
.modal-content { background: white; margin: 50px auto; padding: 20px; width: 80%; max-width: 800px; border-radius: 5px; }
|
||||
.close { float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
|
||||
.email-body { white-space: pre-wrap; background: #f8f9fa; padding: 15px; border-radius: 5px; margin-top: 10px; }
|
||||
</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>邮箱管理 <?php if ($isAdmin): ?>(全部邮件)<?php else: ?>(我的收件箱)<?php endif; ?></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; ?>
|
||||
|
||||
<p>共 <?php echo $totalEmails; ?> 封邮件</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>发件人</th>
|
||||
<th>收件人</th>
|
||||
<th>主题</th>
|
||||
<th>状态</th>
|
||||
<th>时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($emails)): ?>
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center; padding: 40px;">
|
||||
暂无邮件
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($emails as $email): ?>
|
||||
<tr class="<?php echo $email['is_read'] ? '' : 'email-unread'; ?>">
|
||||
<td><?php echo $email['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($email['sender_name'] ?? $email['sender'] ?? '未知'); ?></td>
|
||||
<td><?php echo htmlspecialchars($email['recipient_name'] ?? $email['recipient'] ?? '未知'); ?></td>
|
||||
<td class="email-preview">
|
||||
<a href="#" onclick="viewEmail(<?php echo htmlspecialchars(json_encode($email)); ?>); return false;">
|
||||
<?php echo htmlspecialchars($email['subject'] ?? '(无主题)'); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($email['is_read']): ?>
|
||||
<span class="badge badge-read">已读</span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-unread">未读</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $email['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="#" onclick="viewEmail(<?php echo htmlspecialchars(json_encode($email)); ?>); return false;" class="btn btn-primary btn-small">查看</a>
|
||||
<?php if (!$email['is_read']): ?>
|
||||
<a href="?mark_read=<?php echo $email['id']; ?>" class="btn btn-success btn-small">标记已读</a>
|
||||
<?php endif; ?>
|
||||
<a href="?delete=<?php echo $email['id']; ?>" class="btn btn-danger btn-small" onclick="return confirm('确定要删除此邮件吗?');">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php if ($page > 1): ?>
|
||||
<a href="?page=<?php echo $page - 1; ?>">上一页</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
|
||||
<?php if ($i == $page): ?>
|
||||
<span class="current"><?php echo $i; ?></span>
|
||||
<?php else: ?>
|
||||
<a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
||||
|
||||
<?php if ($page < $totalPages): ?>
|
||||
<a href="?page=<?php echo $page + 1; ?>">下一页</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- 查看邮件模态框 -->
|
||||
<div id="emailModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeEmailModal()">×</span>
|
||||
<h3 id="email-subject">邮件详情</h3>
|
||||
<div>
|
||||
<strong>发件人:</strong><span id="email-sender"></span><br>
|
||||
<strong>收件人:</strong><span id="email-recipient"></span><br>
|
||||
<strong>时间:</strong><span id="email-time"></span><br>
|
||||
<strong>主题:</strong><span id="email-subject-text"></span>
|
||||
</div>
|
||||
<div class="email-body" id="email-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function viewEmail(email) {
|
||||
document.getElementById('email-subject').textContent = email.subject || '(无主题)';
|
||||
document.getElementById('email-subject-text').textContent = email.subject || '(无主题)';
|
||||
document.getElementById('email-sender').textContent = email.sender_name || email.sender || '未知';
|
||||
document.getElementById('email-recipient').textContent = email.recipient_name || email.recipient || '未知';
|
||||
document.getElementById('email-time').textContent = email.created_at;
|
||||
document.getElementById('email-body').textContent = email.body || '(无内容)';
|
||||
document.getElementById('emailModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeEmailModal() {
|
||||
document.getElementById('emailModal').style.display = 'none';
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('emailModal');
|
||||
if (event.target == modal) {
|
||||
closeEmailModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
require_once __DIR__ . '/../src/storage/Database.php';
|
||||
require_once __DIR__ . '/../src/storage/EmailRepository.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$emailRepo = new EmailRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理删除邮件
|
||||
if (isset($_GET['delete'])) {
|
||||
$emailId = (int)$_GET['delete'];
|
||||
if ($emailRepo->delete($emailId)) {
|
||||
$message = "邮件删除成功";
|
||||
} else {
|
||||
$error = "删除失败";
|
||||
}
|
||||
}
|
||||
|
||||
// 处理标记已读
|
||||
if (isset($_GET['mark_read'])) {
|
||||
$emailId = (int)$_GET['mark_read'];
|
||||
if ($emailRepo->markAsRead($emailId)) {
|
||||
$message = "邮件已标记为已读";
|
||||
}
|
||||
}
|
||||
|
||||
// 获取邮件列表
|
||||
$isAdmin = $_SESSION['is_admin'] ?? false;
|
||||
$userId = $_SESSION['user_id'];
|
||||
|
||||
// 分页参数
|
||||
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
|
||||
$perPage = 20;
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
// 获取邮件
|
||||
if ($isAdmin) {
|
||||
$emails = $emailRepo->getAll($perPage, $offset);
|
||||
$totalEmails = $emailRepo->getCount();
|
||||
} else {
|
||||
$emails = $emailRepo->getInbox($userId, $perPage, $offset);
|
||||
$totalEmails = $emailRepo->getCount($userId);
|
||||
}
|
||||
|
||||
$totalPages = ceil($totalEmails / $perPage);
|
||||
?>
|
||||
<!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; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
th { background: #f8f9fa; font-weight: 600; }
|
||||
tr:hover { background: #f8f9fa; }
|
||||
.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-small { padding: 4px 8px; font-size: 12px; }
|
||||
.badge { padding: 4px 8px; border-radius: 3px; font-size: 12px; font-weight: 500; }
|
||||
.badge-read { background: #6c757d; color: white; }
|
||||
.badge-unread { background: #007bff; color: white; }
|
||||
.email-unread { font-weight: bold; }
|
||||
.pagination { margin-top: 20px; text-align: center; }
|
||||
.pagination a { display: inline-block; padding: 8px 12px; margin: 0 4px; text-decoration: none; border: 1px solid #ddd; border-radius: 4px; }
|
||||
.pagination a:hover { background: #f8f9fa; }
|
||||
.pagination .current { background: #007bff; color: white; border-color: #007bff; }
|
||||
.email-preview { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); overflow: auto; }
|
||||
.modal-content { background: white; margin: 50px auto; padding: 20px; width: 80%; max-width: 800px; border-radius: 5px; }
|
||||
.close { float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
|
||||
.email-body { white-space: pre-wrap; background: #f8f9fa; padding: 15px; border-radius: 5px; margin-top: 10px; }
|
||||
</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 ($isAdmin): ?>
|
||||
<a href="users.php">用户管理</a>
|
||||
<?php endif; ?>
|
||||
<a href="emails.php">邮件管理</a>
|
||||
<a href="filters.php">过滤规则</a>
|
||||
<a href="logs.php">系统日志</a>
|
||||
<?php if ($isAdmin): ?>
|
||||
<a href="settings.php">系统设置</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2>邮件管理 <?php if ($isAdmin): ?>(全部邮件)<?php else: ?>(我的收件箱)<?php endif; ?></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; ?>
|
||||
|
||||
<p>共 <?php echo $totalEmails; ?> 封邮件</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>发件人</th>
|
||||
<th>收件人</th>
|
||||
<th>主题</th>
|
||||
<th>状态</th>
|
||||
<th>时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($emails)): ?>
|
||||
<tr>
|
||||
<td colspan="7" style="text-align: center; padding: 40px;">
|
||||
暂无邮件
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($emails as $email): ?>
|
||||
<tr class="<?php echo $email['is_read'] ? '' : 'email-unread'; ?>">
|
||||
<td><?php echo $email['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($email['sender_name'] ?? $email['sender'] ?? '未知'); ?></td>
|
||||
<td><?php echo htmlspecialchars($email['recipient_name'] ?? $email['recipient'] ?? '未知'); ?></td>
|
||||
<td class="email-preview">
|
||||
<a href="#" onclick="viewEmail(<?php echo htmlspecialchars(json_encode($email)); ?>); return false;">
|
||||
<?php echo htmlspecialchars($email['subject'] ?? '(无主题)'); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($email['is_read']): ?>
|
||||
<span class="badge badge-read">已读</span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-unread">未读</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $email['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="#" onclick="viewEmail(<?php echo htmlspecialchars(json_encode($email)); ?>); return false;" class="btn btn-primary btn-small">查看</a>
|
||||
<?php if (!$email['is_read']): ?>
|
||||
<a href="?mark_read=<?php echo $email['id']; ?>" class="btn btn-success btn-small">标记已读</a>
|
||||
<?php endif; ?>
|
||||
<a href="?delete=<?php echo $email['id']; ?>" class="btn btn-danger btn-small" onclick="return confirm('确定要删除此邮件吗?');">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php if ($page > 1): ?>
|
||||
<a href="?page=<?php echo $page - 1; ?>">上一页</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
|
||||
<?php if ($i == $page): ?>
|
||||
<span class="current"><?php echo $i; ?></span>
|
||||
<?php else: ?>
|
||||
<a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
||||
|
||||
<?php if ($page < $totalPages): ?>
|
||||
<a href="?page=<?php echo $page + 1; ?>">下一页</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- 查看邮件模态框 -->
|
||||
<div id="emailModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeEmailModal()">×</span>
|
||||
<h3 id="email-subject">邮件详情</h3>
|
||||
<div>
|
||||
<strong>发件人:</strong><span id="email-sender"></span><br>
|
||||
<strong>收件人:</strong><span id="email-recipient"></span><br>
|
||||
<strong>时间:</strong><span id="email-time"></span><br>
|
||||
<strong>主题:</strong><span id="email-subject-text"></span>
|
||||
</div>
|
||||
<div class="email-body" id="email-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function viewEmail(email) {
|
||||
document.getElementById('email-subject').textContent = email.subject || '(无主题)';
|
||||
document.getElementById('email-subject-text').textContent = email.subject || '(无主题)';
|
||||
document.getElementById('email-sender').textContent = email.sender_name || email.sender || '未知';
|
||||
document.getElementById('email-recipient').textContent = email.recipient_name || email.recipient || '未知';
|
||||
document.getElementById('email-time').textContent = email.created_at;
|
||||
document.getElementById('email-body').textContent = email.body || '(无内容)';
|
||||
document.getElementById('emailModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeEmailModal() {
|
||||
document.getElementById('emailModal').style.display = 'none';
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('emailModal');
|
||||
if (event.target == modal) {
|
||||
closeEmailModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@ -1,257 +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';
|
||||
|
||||
//开启所有错误日志报告
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$filterRepo = new FilterRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
if (isset($_POST['toggle_id'])) {
|
||||
$id = (int)$_POST['toggle_id'];
|
||||
$row = $filterRepo->getById($id);
|
||||
if ($row) {
|
||||
$filterRepo->updateStatus($id, !(bool)$row['is_active']);
|
||||
}
|
||||
header('Location: filters.php'); // 302 跳回干净地址
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 处理创建过滤规则
|
||||
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'];
|
||||
$row = $filterRepo->getById($id); // 改用 public 方法
|
||||
if ($row) {
|
||||
$newStatus = !(bool)$row['is_active'];
|
||||
if ($filterRepo->updateStatus($id, $newStatus)) {
|
||||
$message = "规则状态已更新";
|
||||
} else {
|
||||
$error = "更新失败";
|
||||
}
|
||||
} 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>
|
||||
<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; ?>
|
||||
|
||||
<!-- 创建过滤规则 -->
|
||||
<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>
|
||||
<form method="post" style="display:inline;">
|
||||
<input type="hidden" name="toggle_id" value="<?php echo $rule['id']; ?>">
|
||||
<button type="submit" class="btn btn-warning">
|
||||
<?php echo $rule['is_active'] ? '禁用' : '启用'; ?>
|
||||
</button>
|
||||
</form>
|
||||
<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>
|
||||
|
||||
<?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>
|
||||
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// 清除所有会话数据
|
||||
$_SESSION = array();
|
||||
|
||||
// 销毁会话cookie
|
||||
if (isset($_COOKIE[session_name()])) {
|
||||
setcookie(session_name(), '', time()-3600, '/');
|
||||
}
|
||||
|
||||
// 销毁会话
|
||||
session_destroy();
|
||||
|
||||
// 重定向到登录页面
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// 清除所有会话数据
|
||||
$_SESSION = array();
|
||||
|
||||
// 销毁会话cookie
|
||||
if (isset($_COOKIE[session_name()])) {
|
||||
setcookie(session_name(), '', time()-3600, '/');
|
||||
}
|
||||
|
||||
// 销毁会话
|
||||
session_destroy();
|
||||
|
||||
// 重定向到登录页面
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
|
||||
|
||||
@ -1,299 +1,292 @@
|
||||
<?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/utils/Validator.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
require_once __DIR__ . '/../src/storage/SystemSettingsRepository.php';
|
||||
|
||||
session_start();
|
||||
|
||||
// 身份验证
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$settingsRepo = new SystemSettingsRepository();
|
||||
// 获取域名设置(放在函数定义之前)
|
||||
$domain = $settingsRepo->get('domain', 'test.com');
|
||||
|
||||
$userRepo = new UserRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理创建用户
|
||||
if (isset($_POST['create_user'])) {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$isAdmin = isset($_POST['is_admin']) ? 1 : 0;
|
||||
$isActive = isset($_POST['is_active']) ? 1 : 0;
|
||||
|
||||
$usernameValidation = Validator::validateUsername($username);
|
||||
if (!$usernameValidation['valid']) {
|
||||
$error = implode('<br>', $usernameValidation['errors']);
|
||||
} else {
|
||||
if (!Validator::validateEmailDomain($username, $domain)) {
|
||||
$error = "邮箱域名必须是 @".$domain;
|
||||
} else {
|
||||
$passwordValidation = Validator::validatePassword($password, 6);
|
||||
if (!$passwordValidation['valid']) {
|
||||
$error = implode('<br>', $passwordValidation['errors']);
|
||||
} else {
|
||||
try {
|
||||
if ($userRepo->usernameExists($username)) {
|
||||
$error = "用户名已存在";
|
||||
} else {
|
||||
$userRepo->create($username, $password, $isAdmin, $isActive);
|
||||
$message = "用户创建成功";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$error = "创建失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理更新用户
|
||||
if (isset($_POST['update_user'])) {
|
||||
$userId = (int)$_POST['user_id'];
|
||||
$data = [];
|
||||
|
||||
if (!empty($_POST['new_password'])) {
|
||||
$passwordValidation = Validator::validatePassword($_POST['new_password'], 6);
|
||||
if (!$passwordValidation['valid']) {
|
||||
$error = implode('<br>', $passwordValidation['errors']);
|
||||
} else {
|
||||
$data['password'] = $_POST['new_password'];
|
||||
}
|
||||
}
|
||||
|
||||
/**if (isset($_POST['is_admin'])) {
|
||||
$data['is_admin'] = (int)$_POST['is_admin'];
|
||||
}
|
||||
|
||||
if (isset($_POST['is_active'])) {
|
||||
$data['is_active'] = (int)$_POST['is_active'];
|
||||
}**/
|
||||
// 管理员权限总是更新
|
||||
$data['is_admin'] = isset($_POST['is_admin']) ? 1 : 0;
|
||||
|
||||
// 激活状态也是
|
||||
$data['is_active'] = isset($_POST['is_active']) ? 1 : 0;
|
||||
|
||||
if (empty($error) && !empty($data)) {
|
||||
if ($userRepo->update($userId, $data)) {
|
||||
$message = "用户更新成功";
|
||||
} else {
|
||||
$error = "更新失败";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除用户
|
||||
if (isset($_GET['delete'])) {
|
||||
$userId = (int)$_GET['delete'];
|
||||
if ($userId != $_SESSION['user_id']) { // 不能删除自己
|
||||
if ($userRepo->delete($userId)) {
|
||||
$message = "用户删除成功";
|
||||
} else {
|
||||
$error = "删除失败";
|
||||
}
|
||||
} else {
|
||||
$error = "不能删除自己的账号";
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有用户
|
||||
$users = $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); }
|
||||
.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; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
th { background: #f8f9fa; font-weight: 600; }
|
||||
tr:hover { background: #f8f9fa; }
|
||||
.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-small { padding: 4px 8px; font-size: 12px; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; font-weight: 500; }
|
||||
.form-group input, .form-group select { width: 100%; 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; }
|
||||
.badge { padding: 4px 8px; border-radius: 3px; font-size: 12px; font-weight: 500; }
|
||||
.badge-admin { background: #ffc107; color: #000; }
|
||||
.badge-active { background: #28a745; color: white; }
|
||||
.badge-inactive { background: #6c757d; color: white; }
|
||||
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
|
||||
.modal-content { background: white; margin: 50px auto; padding: 20px; width: 500px; border-radius: 5px; }
|
||||
.close { float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
|
||||
</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; ?>
|
||||
|
||||
<!-- 创建用户表单 -->
|
||||
<h3>创建新用户</h3>
|
||||
<form method="POST" class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>邮箱地址</label>
|
||||
<input type="email" name="username" placeholder="user@<?= htmlspecialchars($domain) ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>密码</label>
|
||||
<input type="password" name="password" placeholder="至少6个字符" required minlength="6">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>管理员</label>
|
||||
<input type="checkbox" name="is_admin" value="1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>激活</label>
|
||||
<input type="checkbox" name="is_active" value="1" checked>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" name="create_user" class="btn btn-primary">创建用户</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 用户列表 -->
|
||||
<h3>用户列表 (<?php echo count($users); ?>)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>用户名</th>
|
||||
<th>角色</th>
|
||||
<th>状态</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<td><?php echo $user['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||
<td>
|
||||
<?php if ($user['is_admin']): ?>
|
||||
<span class="badge badge-admin">管理员</span>
|
||||
<?php else: ?>
|
||||
<span>普通用户</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($user['is_active']): ?>
|
||||
<span class="badge badge-active">激活</span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-inactive">禁用</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $user['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="#" onclick="editUser(<?php echo htmlspecialchars(json_encode($user)); ?>); return false;" class="btn btn-primary btn-small">编辑</a>
|
||||
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="?delete=<?php echo $user['id']; ?>" class="btn btn-danger btn-small" onclick="return confirm('确定要删除此用户吗?');">删除</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 编辑用户模态框 -->
|
||||
<div id="editModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeModal()">×</span>
|
||||
<h3>编辑用户</h3>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="user_id" id="edit_user_id">
|
||||
<div class="form-group">
|
||||
<label>用户名</label>
|
||||
<input type="text" id="edit_username" readonly style="background: #f5f5f5;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>新密码(留空则不修改)</label>
|
||||
<input type="password" name="new_password" placeholder="留空则不修改">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="is_admin" id="edit_is_admin" value="1"> 管理员
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="is_active" id="edit_is_active" value="1"> 激活
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" name="update_user" class="btn btn-success">保存</button>
|
||||
<button type="button" onclick="closeModal()" class="btn">取消</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function editUser(user) {
|
||||
document.getElementById('edit_user_id').value = user.id;
|
||||
document.getElementById('edit_username').value = user.username;
|
||||
document.getElementById('edit_is_admin').checked = user.is_admin == 1;
|
||||
document.getElementById('edit_is_active').checked = user.is_active == 1;
|
||||
document.getElementById('editModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('editModal').style.display = 'none';
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('editModal');
|
||||
if (event.target == modal) {
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?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/utils/Validator.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('权限不足:只有管理员可以访问此页面');
|
||||
}
|
||||
|
||||
$userRepo = new UserRepository();
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
// 处理创建用户
|
||||
if (isset($_POST['create_user'])) {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$isAdmin = isset($_POST['is_admin']) ? 1 : 0;
|
||||
$isActive = isset($_POST['is_active']) ? 1 : 0;
|
||||
|
||||
$usernameValidation = Validator::validateUsername($username);
|
||||
if (!$usernameValidation['valid']) {
|
||||
$error = implode('<br>', $usernameValidation['errors']);
|
||||
} else {
|
||||
if (!Validator::validateEmailDomain($username, 'test.com')) {
|
||||
$error = "邮箱域名必须是 @test.com";
|
||||
} else {
|
||||
$passwordValidation = Validator::validatePassword($password, 6);
|
||||
if (!$passwordValidation['valid']) {
|
||||
$error = implode('<br>', $passwordValidation['errors']);
|
||||
} else {
|
||||
try {
|
||||
if ($userRepo->usernameExists($username)) {
|
||||
$error = "用户名已存在";
|
||||
} else {
|
||||
$userRepo->create($username, $password, $isAdmin, $isActive);
|
||||
$message = "用户创建成功";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$error = "创建失败: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理更新用户
|
||||
if (isset($_POST['update_user'])) {
|
||||
$userId = (int)$_POST['user_id'];
|
||||
$data = [];
|
||||
|
||||
if (!empty($_POST['new_password'])) {
|
||||
$passwordValidation = Validator::validatePassword($_POST['new_password'], 6);
|
||||
if (!$passwordValidation['valid']) {
|
||||
$error = implode('<br>', $passwordValidation['errors']);
|
||||
} else {
|
||||
$data['password'] = $_POST['new_password'];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['is_admin'])) {
|
||||
$data['is_admin'] = (int)$_POST['is_admin'];
|
||||
}
|
||||
|
||||
if (isset($_POST['is_active'])) {
|
||||
$data['is_active'] = (int)$_POST['is_active'];
|
||||
}
|
||||
|
||||
if (empty($error) && !empty($data)) {
|
||||
if ($userRepo->update($userId, $data)) {
|
||||
$message = "用户更新成功";
|
||||
} else {
|
||||
$error = "更新失败";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理删除用户
|
||||
if (isset($_GET['delete'])) {
|
||||
$userId = (int)$_GET['delete'];
|
||||
if ($userId != $_SESSION['user_id']) { // 不能删除自己
|
||||
if ($userRepo->delete($userId)) {
|
||||
$message = "用户删除成功";
|
||||
} else {
|
||||
$error = "删除失败";
|
||||
}
|
||||
} else {
|
||||
$error = "不能删除自己的账号";
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有用户
|
||||
$users = $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); }
|
||||
.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; }
|
||||
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
|
||||
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
|
||||
th { background: #f8f9fa; font-weight: 600; }
|
||||
tr:hover { background: #f8f9fa; }
|
||||
.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-small { padding: 4px 8px; font-size: 12px; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; font-weight: 500; }
|
||||
.form-group input, .form-group select { width: 100%; 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; }
|
||||
.badge { padding: 4px 8px; border-radius: 3px; font-size: 12px; font-weight: 500; }
|
||||
.badge-admin { background: #ffc107; color: #000; }
|
||||
.badge-active { background: #28a745; color: white; }
|
||||
.badge-inactive { background: #6c757d; color: white; }
|
||||
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); }
|
||||
.modal-content { background: white; margin: 50px auto; padding: 20px; width: 500px; border-radius: 5px; }
|
||||
.close { float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
|
||||
</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="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; ?>
|
||||
|
||||
<!-- 创建用户表单 -->
|
||||
<h3>创建新用户</h3>
|
||||
<form method="POST" class="form-inline">
|
||||
<div class="form-group">
|
||||
<label>邮箱地址</label>
|
||||
<input type="email" name="username" placeholder="user@test.com" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>密码</label>
|
||||
<input type="password" name="password" placeholder="至少6个字符" required minlength="6">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>管理员</label>
|
||||
<input type="checkbox" name="is_admin" value="1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>激活</label>
|
||||
<input type="checkbox" name="is_active" value="1" checked>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" name="create_user" class="btn btn-primary">创建用户</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 用户列表 -->
|
||||
<h3>用户列表 (<?php echo count($users); ?>)</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>用户名</th>
|
||||
<th>角色</th>
|
||||
<th>状态</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<td><?php echo $user['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||
<td>
|
||||
<?php if ($user['is_admin']): ?>
|
||||
<span class="badge badge-admin">管理员</span>
|
||||
<?php else: ?>
|
||||
<span>普通用户</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($user['is_active']): ?>
|
||||
<span class="badge badge-active">激活</span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-inactive">禁用</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $user['created_at']; ?></td>
|
||||
<td>
|
||||
<a href="#" onclick="editUser(<?php echo htmlspecialchars(json_encode($user)); ?>); return false;" class="btn btn-primary btn-small">编辑</a>
|
||||
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="?delete=<?php echo $user['id']; ?>" class="btn btn-danger btn-small" onclick="return confirm('确定要删除此用户吗?');">删除</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 编辑用户模态框 -->
|
||||
<div id="editModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" onclick="closeModal()">×</span>
|
||||
<h3>编辑用户</h3>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="user_id" id="edit_user_id">
|
||||
<div class="form-group">
|
||||
<label>用户名</label>
|
||||
<input type="text" id="edit_username" readonly style="background: #f5f5f5;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>新密码(留空则不修改)</label>
|
||||
<input type="password" name="new_password" placeholder="留空则不修改">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="is_admin" id="edit_is_admin" value="1"> 管理员
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="is_active" id="edit_is_active" value="1"> 激活
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" name="update_user" class="btn btn-success">保存</button>
|
||||
<button type="button" onclick="closeModal()" class="btn">取消</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function editUser(user) {
|
||||
document.getElementById('edit_user_id').value = user.id;
|
||||
document.getElementById('edit_username').value = user.username;
|
||||
document.getElementById('edit_is_admin').checked = user.is_admin == 1;
|
||||
document.getElementById('edit_is_active').checked = user.is_active == 1;
|
||||
document.getElementById('editModal').style.display = 'block';
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('editModal').style.display = 'none';
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('editModal');
|
||||
if (event.target == modal) {
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@ -1,106 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* 测试用户注册功能
|
||||
* 用法: php scripts/test_register.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/utils/Validator.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
echo "=== 用户注册功能测试 ===\n\n";
|
||||
|
||||
try {
|
||||
$userRepo = new UserRepository();
|
||||
|
||||
// 测试1: 验证邮箱格式
|
||||
echo "测试1: 验证邮箱格式\n";
|
||||
$testEmails = [
|
||||
'valid@test.com' => true,
|
||||
'invalid-email' => false,
|
||||
'test@test.com' => true,
|
||||
'user@wrong.com' => false,
|
||||
];
|
||||
|
||||
foreach ($testEmails as $email => $expected) {
|
||||
$isValid = Validator::validateEmail($email);
|
||||
$domainValid = Validator::validateEmailDomain($email, 'test.com');
|
||||
$result = $isValid && ($expected ? $domainValid : !$domainValid);
|
||||
echo " {$email}: " . ($result ? "✓" : "✗") . "\n";
|
||||
}
|
||||
|
||||
// 测试2: 验证密码强度
|
||||
echo "\n测试2: 验证密码强度\n";
|
||||
$testPasswords = [
|
||||
'12345' => false, // 太短
|
||||
'123456' => true, // 符合最小长度
|
||||
'password123' => true,
|
||||
];
|
||||
|
||||
foreach ($testPasswords as $password => $expected) {
|
||||
$validation = Validator::validatePassword($password, 6);
|
||||
$result = $validation['valid'] === $expected;
|
||||
echo " '{$password}': " . ($result ? "✓" : "✗") . "\n";
|
||||
if (!$validation['valid']) {
|
||||
echo " 错误: " . implode(', ', $validation['errors']) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试3: 检查用户名是否存在
|
||||
echo "\n测试3: 检查用户名是否存在\n";
|
||||
$existingUser = $userRepo->findByUsername('admin@test.com');
|
||||
if ($existingUser) {
|
||||
echo " admin@test.com 存在: ✓\n";
|
||||
} else {
|
||||
echo " admin@test.com 不存在: ✗\n";
|
||||
}
|
||||
|
||||
// 测试4: 创建测试用户(如果不存在)
|
||||
echo "\n测试4: 创建测试用户\n";
|
||||
$testUsername = 'testuser@test.com';
|
||||
|
||||
if ($userRepo->usernameExists($testUsername)) {
|
||||
echo " 测试用户已存在,跳过创建\n";
|
||||
} else {
|
||||
try {
|
||||
$newUser = $userRepo->create($testUsername, 'test123456', false, true);
|
||||
echo " 创建用户成功: ✓\n";
|
||||
echo " 用户ID: {$newUser['id']}\n";
|
||||
echo " 用户名: {$newUser['username']}\n";
|
||||
echo " 是否管理员: " . ($newUser['is_admin'] ? '是' : '否') . "\n";
|
||||
} catch (Exception $e) {
|
||||
echo " 创建用户失败: ✗ - " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试5: 验证密码
|
||||
echo "\n测试5: 验证密码\n";
|
||||
$testUser = $userRepo->findByUsername($testUsername);
|
||||
if ($testUser) {
|
||||
$verified = $userRepo->verifyPassword($testUsername, 'test123456');
|
||||
if ($verified) {
|
||||
echo " 密码验证成功: ✓\n";
|
||||
} else {
|
||||
echo " 密码验证失败: ✗\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试6: 获取所有用户
|
||||
echo "\n测试6: 获取用户列表\n";
|
||||
$users = $userRepo->getAll(10);
|
||||
echo " 用户总数: " . count($users) . "\n";
|
||||
foreach ($users as $user) {
|
||||
echo " - {$user['username']} (ID: {$user['id']}, " .
|
||||
($user['is_admin'] ? '管理员' : '普通用户') . ", " .
|
||||
($user['is_active'] ? '激活' : '禁用') . ")\n";
|
||||
}
|
||||
|
||||
echo "\n=== 测试完成 ===\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "错误: " . $e->getMessage() . "\n";
|
||||
echo "堆栈跟踪:\n" . $e->getTraceAsString() . "\n";
|
||||
}
|
||||
|
||||
<?php
|
||||
/**
|
||||
* 测试用户注册功能
|
||||
* 用法: php scripts/test_register.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/utils/Validator.php';
|
||||
require_once __DIR__ . '/../src/utils/Security.php';
|
||||
|
||||
echo "=== 用户注册功能测试 ===\n\n";
|
||||
|
||||
try {
|
||||
$userRepo = new UserRepository();
|
||||
|
||||
// 测试1: 验证邮箱格式
|
||||
echo "测试1: 验证邮箱格式\n";
|
||||
$testEmails = [
|
||||
'valid@test.com' => true,
|
||||
'invalid-email' => false,
|
||||
'test@test.com' => true,
|
||||
'user@wrong.com' => false,
|
||||
];
|
||||
|
||||
foreach ($testEmails as $email => $expected) {
|
||||
$isValid = Validator::validateEmail($email);
|
||||
$domainValid = Validator::validateEmailDomain($email, 'test.com');
|
||||
$result = $isValid && ($expected ? $domainValid : !$domainValid);
|
||||
echo " {$email}: " . ($result ? "✓" : "✗") . "\n";
|
||||
}
|
||||
|
||||
// 测试2: 验证密码强度
|
||||
echo "\n测试2: 验证密码强度\n";
|
||||
$testPasswords = [
|
||||
'12345' => false, // 太短
|
||||
'123456' => true, // 符合最小长度
|
||||
'password123' => true,
|
||||
];
|
||||
|
||||
foreach ($testPasswords as $password => $expected) {
|
||||
$validation = Validator::validatePassword($password, 6);
|
||||
$result = $validation['valid'] === $expected;
|
||||
echo " '{$password}': " . ($result ? "✓" : "✗") . "\n";
|
||||
if (!$validation['valid']) {
|
||||
echo " 错误: " . implode(', ', $validation['errors']) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试3: 检查用户名是否存在
|
||||
echo "\n测试3: 检查用户名是否存在\n";
|
||||
$existingUser = $userRepo->findByUsername('admin@test.com');
|
||||
if ($existingUser) {
|
||||
echo " admin@test.com 存在: ✓\n";
|
||||
} else {
|
||||
echo " admin@test.com 不存在: ✗\n";
|
||||
}
|
||||
|
||||
// 测试4: 创建测试用户(如果不存在)
|
||||
echo "\n测试4: 创建测试用户\n";
|
||||
$testUsername = 'testuser@test.com';
|
||||
|
||||
if ($userRepo->usernameExists($testUsername)) {
|
||||
echo " 测试用户已存在,跳过创建\n";
|
||||
} else {
|
||||
try {
|
||||
$newUser = $userRepo->create($testUsername, 'test123456', false, true);
|
||||
echo " 创建用户成功: ✓\n";
|
||||
echo " 用户ID: {$newUser['id']}\n";
|
||||
echo " 用户名: {$newUser['username']}\n";
|
||||
echo " 是否管理员: " . ($newUser['is_admin'] ? '是' : '否') . "\n";
|
||||
} catch (Exception $e) {
|
||||
echo " 创建用户失败: ✗ - " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试5: 验证密码
|
||||
echo "\n测试5: 验证密码\n";
|
||||
$testUser = $userRepo->findByUsername($testUsername);
|
||||
if ($testUser) {
|
||||
$verified = $userRepo->verifyPassword($testUsername, 'test123456');
|
||||
if ($verified) {
|
||||
echo " 密码验证成功: ✓\n";
|
||||
} else {
|
||||
echo " 密码验证失败: ✗\n";
|
||||
}
|
||||
}
|
||||
|
||||
// 测试6: 获取所有用户
|
||||
echo "\n测试6: 获取用户列表\n";
|
||||
$users = $userRepo->getAll(10);
|
||||
echo " 用户总数: " . count($users) . "\n";
|
||||
foreach ($users as $user) {
|
||||
echo " - {$user['username']} (ID: {$user['id']}, " .
|
||||
($user['is_admin'] ? '管理员' : '普通用户') . ", " .
|
||||
($user['is_active'] ? '激活' : '禁用') . ")\n";
|
||||
}
|
||||
|
||||
echo "\n=== 测试完成 ===\n";
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "错误: " . $e->getMessage() . "\n";
|
||||
echo "堆栈跟踪:\n" . $e->getTraceAsString() . "\n";
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
//处理管理请求
|
||||
@ -1,150 +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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
<?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
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../storage/Database.php';
|
||||
|
||||
/**
|
||||
* 一次性把 users.username 中 @oldDomain 批量替换成 @newDomain
|
||||
*/
|
||||
class SyncDomainService
|
||||
{
|
||||
private $db;
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int 实际被更新的用户数
|
||||
*/
|
||||
public function run(string $oldDomain, string $newDomain): int
|
||||
{
|
||||
// 防止注入,直接用 REPLACE 函数最省事
|
||||
$sql = "UPDATE users
|
||||
SET username = REPLACE(username, :old, :new)
|
||||
WHERE username LIKE :like";
|
||||
$stmt = $this->db->prepare($sql);
|
||||
$stmt->execute([
|
||||
':old' => '@' . $oldDomain,
|
||||
':new' => '@' . $newDomain,
|
||||
':like' => '%@' . $oldDomain
|
||||
]);
|
||||
return $stmt->rowCount();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
// 管理后台网页" - 网页界面
|
||||
@ -1,121 +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]);
|
||||
$this->db->commit();
|
||||
}
|
||||
|
||||
public function getById(int $id): ?array
|
||||
{
|
||||
$stmt = $this->db->prepare("SELECT * FROM filter_rules WHERE id = ? LIMIT 1");
|
||||
$stmt->execute([$id]);
|
||||
return $stmt->fetch() ?: null;
|
||||
}
|
||||
}
|
||||
<?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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,84 +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)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
<?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)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,79 +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'];
|
||||
}
|
||||
}
|
||||
|
||||
<?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'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,56 +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;
|
||||
}
|
||||
}
|
||||
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
#!/bin/bash
|
||||
echo "测试SMTP服务器..."
|
||||
|
||||
# 启动服务器(后台运行)
|
||||
sudo php scripts/start_smtp.php &
|
||||
SERVER_PID=$!
|
||||
sleep 3 # 等待更长时间确保服务器启动
|
||||
|
||||
echo "发送测试邮件..."
|
||||
# 使用timeout防止telnet无限等待
|
||||
timeout 5 telnet localhost 25 << 'EOF'
|
||||
HELO test
|
||||
MAIL FROM: <user1@test.com>
|
||||
RCPT TO: <admin@test.com>
|
||||
DATA
|
||||
Subject: 自动测试邮件
|
||||
From: user1@test.com
|
||||
To: admin@test.com
|
||||
|
||||
这是自动发送的测试邮件
|
||||
.
|
||||
QUIT
|
||||
EOF
|
||||
|
||||
# 等待服务器处理完成
|
||||
sleep 2
|
||||
|
||||
|
||||
kill $SERVER_PID 2>/dev/null
|
||||
#!/bin/bash
|
||||
echo "测试SMTP服务器..."
|
||||
|
||||
# 启动服务器(后台运行)
|
||||
sudo php scripts/start_smtp.php &
|
||||
SERVER_PID=$!
|
||||
sleep 3 # 等待更长时间确保服务器启动
|
||||
|
||||
echo "发送测试邮件..."
|
||||
# 使用timeout防止telnet无限等待
|
||||
timeout 5 telnet localhost 25 << 'EOF'
|
||||
HELO test
|
||||
MAIL FROM: <user1@test.com>
|
||||
RCPT TO: <admin@test.com>
|
||||
DATA
|
||||
Subject: 自动测试邮件
|
||||
From: user1@test.com
|
||||
To: admin@test.com
|
||||
|
||||
这是自动发送的测试邮件
|
||||
.
|
||||
QUIT
|
||||
EOF
|
||||
|
||||
# 等待服务器处理完成
|
||||
sleep 2
|
||||
|
||||
|
||||
kill $SERVER_PID 2>/dev/null
|
||||
echo "测试完成"
|
||||
Loading…
Reference in new issue