实现过滤功能。更新README.md

develop
clumxc 5 months ago
parent f8f3aad04c
commit 9697aa33d0

@ -7,6 +7,7 @@
- Docker & Docker Compose
- PHP 7.4+ (需要扩展: php-mysql, php-sockets)
- WSL2 (Windows环境)
- netstat
## 快速开始
@ -58,21 +59,7 @@ docker-compose exec mysql mysql -umail_user -puser123 mail_server < scripts/crea
- **8080** - Web管理后台
- **8088** - phpMyAdmin管理界面
## 启动服务器
### SMTP服务器发送邮件
```bash
sudo php scripts/start_smtp.php
```
### POP3服务器接收邮件
```bash
sudo php scripts/start_pop3.php
```
**注意**两个服务器需要分别在两个终端运行都需要sudo权限因为使用25和110端口
## Web管理后台
@ -82,6 +69,7 @@ sudo php scripts/start_pop3.php
```bash
cd /mnt/d/mailserver/mailserver/public
php -S localhost:8080
#如果打不开可以尝试换端口为8888或者别的
```
**方式2从项目根目录启动**
@ -97,74 +85,9 @@ php -S localhost:8080 -t public
- 管理员:`admin@test.com` / `123456`
- 普通用户:`user1@test.com` / `123456`
### 功能模块
#### 1. 用户注册
- **页面**`register.php`
- **功能**:新用户注册,邮箱域名限制为 @test.com
#### 2. 用户管理(管理员)
- **页面**`users.php`
- **功能**
- 创建新用户(设置密码、管理员权限、激活状态)
- 编辑用户信息(修改密码、权限、状态)
- 删除用户账号
- 查看用户列表
#### 3. 邮件管理
- **页面**`emails.php`
- **功能**
- 查看邮件(管理员查看全部,普通用户查看自己的收件箱)
- 查看邮件详情
- 标记邮件为已读
- 删除邮件
- 分页浏览
#### 4. 群发邮件(管理员)
- **页面**`broadcast.php`
- **功能**
- 发送给所有用户
- 发送给指定用户列表
- 自定义邮件主题和内容
#### 5. 过滤规则
- **页面**`filters.php`
- **功能**
- 创建邮箱过滤规则(阻止/允许特定邮箱)
- 创建IP地址过滤规则阻止/允许特定IP
- 启用/禁用过滤规则
- 删除过滤规则
#### 6. 系统设置(管理员)
- **页面**`settings.php`
- **功能**
- 设置SMTP端口默认25
- 设置POP3端口默认110
- 设置服务器域名默认test.com
- 设置用户邮箱大小限制
- 设置日志存储路径和最大大小
- 修改管理员密码
#### 7. 服务管理(管理员)
- **页面**`services.php`
- **功能**
- 查看SMTP服务状态
- 查看POP3服务状态
- 启动/停止服务(状态管理)
#### 8. 日志管理
- **页面**`logs.php`
- **功能**
- 查看所有日志
- 按类型过滤SMTP/POP3
- 查看日志统计信息
- 清除日志(管理员)
#### 9. 帮助
- **页面**`help.php`
- **功能**:提供系统使用帮助文档
## 测试方法
## 测试服务器方法
### 测试SMTP发送邮件
@ -215,39 +138,6 @@ RETR 1
QUIT
```
### 测试Web管理后台
1. **用户注册测试**
- 访问http://localhost:8080/register.php
- 注册新用户:`newuser@test.com` / `123456`
- 预期:注册成功,跳转到登录页
2. **用户管理测试(管理员)**
- 登录管理员账号
- 访问http://localhost:8080/users.php
- 创建、编辑、删除用户
3. **群发邮件测试(管理员)**
- 访问http://localhost:8080/broadcast.php
- 选择"发送给所有用户"或"发送给指定用户"
- 填写主题和内容,发送
- 预期:显示成功发送数量
4. **系统设置测试(管理员)**
- 访问http://localhost:8080/settings.php
- 修改端口、域名、邮箱大小等设置
- 修改管理员密码
5. **过滤规则测试**
- 访问http://localhost:8080/filters.php
- 创建邮箱过滤规则和IP过滤规则
- 测试启用/禁用功能
6. **日志管理测试**
- 访问http://localhost:8080/logs.php
- 查看日志列表,按类型过滤
- 测试清除日志功能(管理员)
## 查看数据
### 方法1phpMyAdmin推荐
@ -256,10 +146,10 @@ QUIT
### 方法2命令行
```bash
# 查看用户
docker-compose exec mysql mysql -umail_user -puser123 mail_server -e "SELECT * FROM users;"
docker-compose exec mysql mysql -umail_user -puser123 mailserver -e "SELECT * FROM users;"
# 查看邮件
docker-compose exec mysql mysql -umail_user -puser123 mail_server -e "SELECT id, sender, recipient, subject, created_at FROM emails ORDER BY id DESC;"
docker-compose exec mysql mysql -umail_user -puser123 mailserver -e "SELECT id, sender, recipient, subject, created_at FROM emails ORDER BY id DESC;"
```
## 重置数据库
@ -273,7 +163,33 @@ docker-compose exec mysql mysql -umail_user -puser123 mail_server < scripts/crea
```
## 常见问题
### web页面启停服务器显示端口未成功监听
- 确保web用户有进入目录执行开始脚本的能力可用下面命令测试观察输出。
```bash
#模拟www-data用户执行start_smtp.php脚本
sudo -u www-data php /home/clumxc/projects/mailserver/scripts/start_smtp.php
```
- 需要sudo权限的低端口25、110无法通过Web页面开启需要先改为25252、1100等其它端口
或给 /usr/bin/php 这个可执行文件贴一张“特许证”,以后不管谁运行 php都能绑低端口不需要 root。
一步一步做:
```bash
#给 PHP 贴特许证,打开终端,执行:
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/php
```
```bash
#确认贴上了
getcap /usr/bin/php
#看到输出
/usr/bin/php = cap_net_bind_service+ep
```
```bash
#重启你的 Web 服务(让新能力生效)
#如果你用 Apache
sudo systemctl restart apache2
#如果你用 Nginx + PHP-FPM
sudo systemctl restart php-fpm
```
### 端口被占用
**SMTP服务器启动失败25端口**
@ -404,57 +320,3 @@ mailserver/
7. **✅ 帮助**
- 系统使用帮助文档
### ❌ 移动客户端功能(未完成)
根据课程设计说明书要求Android移动客户端尚未实现
1. **❌ 邮件的操作**
- 邮件的发送
- 邮件的接收
- 邮件的删除
2. **❌ 用户管理**
- 用户修改自己邮箱的账户密码
- 新用户注册功能
3. **❌ 管理员管理**
- 管理员远程登录
- 客户端用户管理(创建、删除、授权、消权、禁用)
## 简要操作指南
### 初始化项目
```bash
# 1. 启动数据库
cd /mnt/d/mailserver/mailserver
docker-compose up -d
sleep 15
# 2. 初始化管理功能数据库表
docker-compose exec mysql mysql -umail_user -puser123 mail_server < scripts/create_admin_tables.sql
# 3. 启动Web服务器
php -S localhost:8080 -t public
```
### 日常使用
```bash
# 启动SMTP服务器终端1
sudo php scripts/start_smtp.php
# 启动POP3服务器终端2
sudo php scripts/start_pop3.php
# 启动Web管理后台终端3
php -S localhost:8080 -t public
```
### 访问地址
- **Web管理后台**http://localhost:8080
- **phpMyAdmin**http://localhost:8088
- **SMTP服务器**localhost:25
- **POP3服务器**localhost:110

@ -1,7 +1,7 @@
启动最简SMTP邮件服务器
==============================
SMTP服务器启动在 0.0.0.0:25252
SMTP服务器启动在 0.0.0.0:25
按 Ctrl+C 停止
数据库连接成功

@ -16,6 +16,15 @@ if (!isset($_SESSION['user_id'])) {
header('Location: index.php');
exit;
}
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;
}
$filterRepo = new FilterRepository();
$message = '';
@ -70,26 +79,22 @@ if (isset($_GET['delete'])) {
// 处理切换规则状态
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'];
$row = $filterRepo->getById($id); // 改用 public 方法
if ($row) {
$newStatus = !(bool)$row['is_active'];
if ($filterRepo->updateStatus($id, $newStatus)) {
$message = "规则状态已更新";
} else {
$error = "更新失败";
$error = "更新失败";
}
} else {
$error = "规则不存在";
}
}
// 获取所有规则
$rules = $filterRepo->getAll();
?>
<!DOCTYPE html>
<html>

@ -40,6 +40,7 @@ class SimpleSmtpServer
// 新增:存储主机和端口
private $host;
private $port;
private $clientIp;
public function __construct($host = '0.0.0.0', $port = 25)
{
@ -106,9 +107,9 @@ class SimpleSmtpServer
// 获取客户端IP地址
socket_getpeername($client, $clientIp);
$clientIp = $clientIp ?: 'unknown';
$this->clientIp = $clientIp;
// 记录连接日志
$this->log("客户端连接", $clientIp);
$this->log("客户端连接",$this->clientIp);
try {
// 1. 说欢迎语
@ -154,12 +155,11 @@ class SimpleSmtpServer
// 提取收件人邮箱
if (preg_match('/<(.+?)>/', $input, $matches)) {
$to = $matches[1];
// 检查收件人邮箱过滤规则
// 新增:收件人过滤
if ($this->filterRepo->isEmailBlocked($to)) {
$this->send($client, "550 Recipient email blocked");
$this->log("收件人邮箱被阻止: {$to}", $clientIp);
continue;
$this->log("收件人邮箱被过滤: {$to}", $this->clientIp);
continue; // 直接拒绝,不加入 $recipients
}
// 初步检查收件人邮箱大小限制(使用估算值,实际检查在接收邮件内容后)
@ -225,7 +225,7 @@ class SimpleSmtpServer
// 9. 保存到数据库(支持多收件人)
$successCount = 0;
foreach ($validRecipients as $to) {
if ($this->saveEmail($from, $to, $emailContent, $clientIp, $emailSize)) {
if ($this->saveEmail($from, $to, $emailContent, $this->clientIp, $emailSize)) {
$successCount++;
}
}

@ -10,8 +10,9 @@ class Database {
private $connection;
private function __construct() {
$config = require __DIR__ . '/../../config/database.php';
$config = require __DIR__ . '/../../config/database.php';
//自动每一条SQL提交一次
// $config['options'][PDO::ATTR_AUTOCOMMIT] = true;
$dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']};charset={$config['charset']}";
try {

@ -109,6 +109,13 @@ class FilterRepository {
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;
}
}
Loading…
Cancel
Save