You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
// === HTTP 头部设置 ===
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header('Content-Type: application/json');
// 处理浏览器的预检请求 (OPTIONS)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
exit(0);
}
// 引入依赖文件
require_once __DIR__ . '/model/DB.php';
require_once __DIR__ . '/service/AuthService.php';
require_once __DIR__ . '/service/SocketClinet.php';
// 获取请求参数
// action: 决定调用哪个功能 (如 login, send_mail)
$action = $_GET['action'] ?? '';
// input: 获取 POST 请求的 JSON Body
$input = json_decode(file_get_contents('php://input'), true) ?? [];
// 获取当前操作的用户名(由前端传过来,用于标识身份)
$currentUser = $input['username'] ?? ($_GET['username'] ?? '');
try {
// === 路由分发 (Routing) ===
switch ($action) {
/* ================== 基础认证模块 ================== */
case 'login':
$username = $input['username'] ?? '';
$password = $input['password'] ?? '';
if (!$username || !$password) {
echo json_encode(['code' => 400, 'msg' => '请输入账号密码']);
break;
}
// 调用 AuthService 进行校验
$data = AuthService::login($username, $password);
if (!$data) {
echo json_encode(['code' => 401, 'msg' => '账号或密码错误']);
} else {
// 登录成功
echo json_encode(['code' => 200, 'data' => $data]);
}
break;
case 'register':
// 简单的注册逻辑:查重 -> 插入
$username = $input['username'] ?? '';
$password = $input['password'] ?? '';
if (!$username || !$password) {
echo json_encode(['code' => 400, 'msg' => '参数不完整']);
break;
}
$pdo = DB::get();
// 检查用户名是否重复
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$username]);
if ($stmt->fetch()) {
echo json_encode(['code' => 400, 'msg' => '用户已存在']);
break;
}
// 插入新用户,密码使用 MD5 加密
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$username, md5($password)]);
echo json_encode(['code' => 200, 'msg' => '注册成功']);
break;
/* ================== 邮件业务模块 ================== */
case 'list_mails':
// 它实际上是在调用 SocketClient 去爬取 POP3 服务器的数据返回给前端。
if (!$currentUser) {
echo json_encode(['code' => 400, 'msg' => '缺少 username']);
break;
}
$pwdForPop3 = $input['password'] ?? '';
if (!$pwdForPop3) {
echo json_encode(['code'=>401,'msg'=>'缺少密码']);
break;
}
try {
// 调用 Socket 客户端去收信
$rows = SocketClient::fetchByPOP3($currentUser, $pwdForPop3);
// 数据清洗:为列表页生成简略预览 (Preview)
foreach ($rows as &$r) {
$body = $r['content'];
// 如果有双换行,通常双换行后面是正文
if(strpos($body, "\r\n\r\n") !== false) {
$body = explode("\r\n\r\n", $body, 2)[1];
}
// 截取前50个字符作为摘要
$r['preview'] = mb_substr(strip_tags($body), 0, 50) . '...';
}
echo json_encode(['code' => 200, 'data' => $rows]);
} catch (Exception $e) {
echo json_encode(['code' => 500, 'msg' => 'POP3错误: ' . $e->getMessage()]);
}
break;
case 'send_mail':
if (!$currentUser) {
echo json_encode(['code' => 400, 'msg' => '未登录']);
break;
}
$to = $input['to'] ?? '';
$subject = $input['subject'] ?? '';
$body = $input['content'] ?? '';
try {
// 调用 Socket 客户端投递邮件
SocketClient::sendBySMTP($currentUser, $to, $subject, $body);
echo json_encode(['code' => 200, 'msg' => 'SMTP投递成功']);
} catch (Exception $e) {
echo json_encode(['code' => 500, 'msg' => 'SMTP错误: ' . $e->getMessage()]);
}
break;
case 'delete_mail':
// 调用 POP3 DELE 命令
$pwdForPop3 = $input['password'] ?? '';
$id = $input['id'] ?? 0;
try {
SocketClient::deleteByPOP3($currentUser, $pwdForPop3, $id);
echo json_encode(['code' => 200, 'msg' => 'POP3删除成功']);
} catch (Exception $e) {
echo json_encode(['code' => 500, 'msg' => $e->getMessage()]);
}
break;
case 'mark_read':
$pdo = DB::get();
$stmt = $pdo->prepare("UPDATE mails SET is_read = 1 WHERE id = ?");
$stmt->execute([$input['id'] ?? 0]);
echo json_encode(['code' => 200, 'msg' => '已标记已读']);
break;
case 'toggle_star':
$pdo = DB::get();
$stmt = $pdo->prepare("UPDATE mails SET is_starred = NOT is_starred WHERE id = ?");
$stmt->execute([$input['id'] ?? 0]);
echo json_encode(['code' => 200, 'msg' => '星标已更新']);
break;
/* ================== 管理员模块 ================== */
case 'list_users':
// 获取用户列表,用于管理面板
$pdo = DB::get();
$stmt = $pdo->query("SELECT id, username, is_admin, is_disabled, used_size, quota_size FROM users");
echo json_encode(['code' => 200, 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
break;
case 'add_user':
// 管理员添加新用户
$pdo = DB::get();
// 查重
$check = $pdo->prepare("SELECT id FROM users WHERE username=?");
$check->execute([$input['target_username']]);
if($check->fetch()) {
echo json_encode(['code' => 400, 'msg' => '用户已存在']);
break;
}
$stmt = $pdo->prepare("INSERT INTO users (username, password, is_admin) VALUES (?, ?, ?)");
$stmt->execute([
$input['target_username'],
md5($input['target_password']),
$input['is_admin'] ?? 0
]);
echo json_encode(['code' => 200, 'msg' => '用户已添加']);
break;
case 'del_user':
// 管理员删除用户
$pdo = DB::get();
$stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$input['uid'] ?? 0]);
echo json_encode(['code' => 200, 'msg' => '用户已删除']);
break;
case 'broadcast':
// 逻辑:遍历所有用户,通过 SocketClient 循环发送 SMTP 邮件
$pdo = DB::get();
$users = $pdo
->query("SELECT username FROM users")
->fetchAll(PDO::FETCH_COLUMN);
$subject = $input['subject'] ?? '系统通知';
$body = $input['content'] ?? 'System Broadcast';
$from = 'admin@system';
foreach ($users as $u) {
try {
if ($u === $from) continue; // 不发给自己
// 复用 sendBySMTP 方法
SocketClient::sendBySMTP(
$from,
$u,
$subject,
$body
);
} catch (Exception $e) {
error_log("Broadcast to {$u} failed: " . $e->getMessage());
}
}
echo json_encode([
'code' => 200,
'msg' => '广播完成'
]);
break;
case 'get_logs':
// 获取服务器日志
$pdo = DB::get();
$stmt = $pdo->query("SELECT * FROM server_logs ORDER BY id DESC LIMIT 50");
echo json_encode(['code' => 200, 'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
break;
case 'change_password':
// 修改密码
if (!$currentUser) { echo json_encode(['code'=>401,'msg'=>'未登录']); break; }
$newPass = $input['new_pass'] ?? '';
if (!$newPass) { echo json_encode(['code'=>400,'msg'=>'密码不能为空']); break; }
$pdo = DB::get();
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE username = ?");
$stmt->execute([md5($newPass), $currentUser]);
echo json_encode(['code' => 200, 'msg' => '密码已修改']);
break;
case 'toggle_status':
// 禁用/解封用户
$uid = $input['uid'] ?? 0;
$pdo = DB::get();
$stmt = $pdo->prepare("UPDATE users SET is_disabled = NOT is_disabled WHERE id = ?");
$stmt->execute([$uid]);
echo json_encode(['code' => 200, 'msg' => '状态已更新']);
break;
case 'list_ip_filters':
// 列出封禁的ip
$pdo = DB::get();
$stmt = $pdo->query("
SELECT
id,
ip_address,
action,
created_at
FROM ip_filters
ORDER BY id DESC
");
echo json_encode([
'code' => 200,
'data' => $stmt->fetchAll(PDO::FETCH_ASSOC)
]);
break;
case 'add_ip_filter':
// 添加封禁ip
$ip = trim($input['ip_address'] ?? '');
if (!$ip) {
echo json_encode(['code' => 400, 'msg' => 'IP 不能为空']);
break;
}
// 简单 IP 格式校验IPv4 / IPv6 都支持)
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
echo json_encode(['code' => 400, 'msg' => 'IP 格式不合法']);
break;
}
$pdo = DB::get();
// 防止重复封禁
$check = $pdo->prepare("
SELECT id
FROM ip_filters
WHERE ip_address = ? AND action = 'BLOCK'
");
$check->execute([$ip]);
if ($check->fetch()) {
echo json_encode(['code' => 400, 'msg' => '该 IP 已被封禁']);
break;
}
$stmt = $pdo->prepare("
INSERT INTO ip_filters (ip_address, action)
VALUES (?, 'BLOCK')
");
$stmt->execute([$ip]);
echo json_encode([
'code' => 200,
'msg' => 'IP 已成功封禁'
]);
break;
case 'del_ip_filter':
// 删除被封禁的ip
$id = intval($input['id'] ?? 0);
if (!$id) {
echo json_encode(['code' => 400, 'msg' => '参数错误']);
break;
}
$pdo = DB::get();
$stmt = $pdo->prepare("DELETE FROM ip_filters WHERE id = ?");
$stmt->execute([$id]);
echo json_encode([
'code' => 200,
'msg' => 'IP 已解封'
]);
break;
default:
echo json_encode(['code' => 404, 'msg' => '接口不存在']);
}
} catch (Exception $e) {
// 全局异常捕获:确保无论发生什么错误,都返回 JSON 格式,防止前端解析崩溃
echo json_encode(['code' => 500, 'msg' => $e->getMessage()]);
}