noumenia/libmilterphp
Composer 安装命令:
composer require noumenia/libmilterphp
包简介
libMilterPHP is a Postfix/Sendmail Milter library implementation in PHP.
README 文档
README
_ _ _ __ __ _ _ _ ____ _ _ ____
| (_) |__ | \/ (_) | |_ ___ _ __| _ \| | | | _ \
| | | '_ \| |\/| | | | __/ _ \ '__| |_) | |_| | |_) |
| | | |_) | | | | | | || __/ | | __/| _ | __/
|_|_|_.__/|_| |_|_|_|_| \___|_| |_| |_| |_|_|
libMilterPHP is a Postfix/Sendmail Milter library implementation in PHP.
Features
- High-performance multi-process
- Low memory footprint
- Strict coding standards
- Support for milter protocol v2, v3 and v4
- Listen on IP address/port or UNIX sockets
- Support for signals
- Proper memory-resident daemon
Requirements
- PHP 8.0, 8.1, 8.2, 8.3, 8.4, 8.5
- libSDManagerPHP
Install with RPM packages
You may install libMilterPHP via the copr repository, for Alma/Rocky/Oracle Enterprise Linux and Fedora, simply use:
dnf copr enable mksanthi/noumenia
dnf install libMilterPHP
Install with Composer
You may install libMilterPHP with composer, to get the latest version use:
composer require noumenia/libmilterphp
Install manually
Download the repository and copy the libMilterPHP project directory in the appropriate place within your project or within an accessibe location, for example under /usr/share/php.
How to use
Loading libraries (RPM package)
Load and initialize the library by loading the common.inc.php file, for each required library:
require_once("/usr/share/php/libLoggerPHP/controller/common.inc.php");
require_once("/usr/share/php/libSDManagerPHP/controller/common.inc.php");
require_once("/usr/share/php/libMilterPHP/controller/common.inc.php");
Loading libraries (composer)
require_once("./vendor/autoload.php");
PHP class
Create your custom class and extend the milter library \libMilterPHP\Milter:
class MilterTestDaemon extends \libMilterPHP\Milter { ... }
Implement your callback functions
Implement all or some of the available callback functions, within your custom class, these functions are:
public function smficAbort(array $message): void // Required
public function smficBody(array $message): void
public function smficConnect(array $message): void
public function smficMacro(array $message): void // Required
public function smficBodyeob(array $message): void // Required
public function smficHelo(array $message): void
public function smficHeader(array $message): void
public function smficMail(array $message): void
public function smficEoh(array $message): void
public function smficRcpt(array $message): void
public function smficQuit(array $message): void // Required
public function smficUnknown(array $message): void
public function smficData(array $message): void
Instantiate your custom class
Instantiate your custom class and pass the configuration parameters to the constructor. These parameters are:
// Create milter object
$milter = new MilterTestDaemon(
"postfix", // Daemon user owner
"mail", // Daemon group owner
"/run/daemon.pid", // PID file
1024, // Process limit
"unix:///run/daemon.sock", // Connection string ("unix:///path/to/file.sock" or "inet:port@IP")
10, // Socket/Stream timeout in seconds
array(SMFIF_QUARANTINE), // Supported actions (array of SMFIF_* constants)
array(SMFIP_NOBODY) // Ignored content (array of SMFIP_* constants)
);
Accept connections
Finally, call the acceptConnections() method, to start the daemon in the foreground:
// Accept connections
$milter->acceptConnections();
Sample milter
The following is a sample milter daemon that checks the FROM and matches it with a known spammer address.
#!/usr/bin/env php
<?php
/**
* Milter test daemon
*
* @copyright Noumenia (C) 2019 - All rights reserved - Software Development - www.noumenia.gr
* @license GNU GPL v3.0
* @package libMilterPHP
* @subpackage miltertestdaemon
*/
if(is_file(__DIR__ . "/vendor/autoload.php")) {
// Autoload via composer
require_once(__DIR__ . "/vendor/autoload.php");
} else {
// Autoload via RPM packages
require_once("/usr/share/php/libLoggerPHP/controller/common.inc.php");
require_once("/usr/share/php/libSDManagerPHP/controller/common.inc.php");
require_once("/usr/share/php/libMilterPHP/controller/common.inc.php");
}
class MilterTestDaemon extends \libMilterPHP\Milter {
/**
* SMFIC_ABORT - Abort current filter checks
* @param array{size: int, command: string, binary: string} $message Message array
* @return void
*/
public function smficAbort(array $message): void
{
// No-op
}
/**
* SMFIC_MAIL - MAIL FROM: information - use SMFIP_NOMAIL to suppress
* @param array{size: int, command: string, binary: string, args: array<string>} $message Message array
* @return void
*/
public function smficMail(array $message): void
{
// Mark this email for quarantine
if(preg_match('/spameri@tiscali\.it/i', strval($message['args'][0])) === 1)
$reply = array('command' => SMFIR_QUARANTINE, 'data' => array('reason' => "Spammer in quarantine!"));
else
$reply = array('command' => SMFIR_CONTINUE, 'data' => array());
$this->reply($reply);
// Since SMFIR_QUARANTINE is a "Modification" action, the MTA is waiting for further commands...
// So continue processing
// Use the helper function
$this->replyContinue();
// Or use the reply function directly
//$reply = array('command' => SMFIR_CONTINUE, 'data' => array());
//$this->reply($reply);
}
/**
* SMFIC_BODYEOB - End of body marker
* @param array{size: int, command: string, binary: string} $message Message array
* @return void
*/
public function smficBodyeob(array $message): void
{
// Use the helper function
$this->replyContinue();
// Or use the reply function directly
//$reply = array('command' => SMFIR_CONTINUE, 'data' => array());
//$this->reply($reply);
// Here is an example for a rejection
//$this->replyReject("Blocked by MilterTestDaemon");
}
}
// Create milter object
$milter = new MilterTestDaemon(
"miltertestuser", // Daemon user owner
"mail", // Daemon group owner
"/run/daemon.pid", // PID file
1024, // Process limit
"unix:///run/daemon.sock", // Connection string ("unix:///path/to/file.sock" or "inet:port@IP")
10, // Socket/Stream timeout in seconds
array(SMFIF_QUARANTINE), // Supported actions (array of SMFIF_* constants)
array( // Ignored content (array of SMFIP_* constants)
SMFIP_NOCONNECT,
SMFIP_NOHELO,
SMFIP_NORCPT,
SMFIP_NOBODY,
SMFIP_NOHDRS,
SMFIP_NOEOH,
SMFIP_NOUNKNOWN,
SMFIP_NODATA
)
// ,2 or ,3 etc // You may set a lower milter protocol version
);
// Accept connections
$milter->acceptConnections();
Notes about SMFIF_* actions
The supported actions array uses SMFIF_* constants, to define which actions MAY be taken by the milter. This is an essential part of the milter/MTA conversation, to define what actions the MTA will expect from the milter. All constants are defined within the libMilterPHP/controller/constants.inc.php file.
Notes about SMFIP_* ignored content
The ignored content array uses SMFIP_* constants, to inform the MTA which parts of the SMTP conversation should NOT be sent to the milter. This feature saves a lot of bandwidth and CPU usage by both the MTA and the milter. All constants are defined within the libMilterPHP/controller/constants.inc.php file.
Notes about SMFIR_* response codes
These constants define various responses that the milter can give to the MTA. The ones marked as "Modification" only make changes to the email data, after a modification the MTA expects the milter to provide another response. The ones marked as "Accept/reject" give a final indication about the email and allow the milter and MTA to end their conversation.
| Constant | Value | Modification | Accept/reject | Asynchronous |
|---|---|---|---|---|
| SMFIR_ADDRCPT | + | [X] | [ ] | [ ] |
| SMFIR_DELRCPT | - | [X] | [ ] | [ ] |
| SMFIR_ACCEPT | a | [ ] | [X] | [ ] |
| SMFIR_REPLBODY | b | [X] | [ ] | [ ] |
| SMFIR_CONTINUE | c | [ ] | [X] | [ ] |
| SMFIR_DISCARD | d | [ ] | [X] | [ ] |
| SMFIR_ADDHEADER | h | [X] | [ ] | [ ] |
| SMFIR_CHGHEADER | m | [X] | [ ] | [ ] |
| SMFIR_PROGRESS | p | [ ] | [ ] | [X] |
| SMFIR_QUARANTINE | q | [X] | [ ] | [ ] |
| SMFIR_REJECT | r | [ ] | [X] | [ ] |
| SMFIR_TEMPFAIL | t | [ ] | [X] | [ ] |
| SMFIR_REPLYCODE | y | [ ] | [X] | [ ] |
Notes about the milter communication protocol
The milter communication protocol runs over UNIX sockets or over an IP/port connection. It uses the following binary format:
size = uint32 (the size of the command+data)
command = char (a one character command)
data = data[size-1] (the data)
For example, the MTA could send a message that in hex looks like:
+----------+---------+--------------------------------+
| size | command | data... |
+----------+---------+----------+----------+----------+
| 0000000d | 4f | 00000006 | 000001ff | 001fffff |
+----------+---------+----------+----------+----------+
The libMilterPHP library will first read the first 4 bytes of the message and interpret it as a uint32 number, which indicates the size of the message that is expected. The library will then keep reading for the whole message and once done, it will separate the command from the data. The command will be used to call the equivalent callback function with the data as a parameter.
Notes about milter protocol versions
version 3
Version 3 adds support for unknown SMTP commands:
- SMFIC_UNKNOWN
- SMFIP_NOUNKNOWN
version 4
Version 4 adds support for the DATA command:
- SMFIC_DATA
- SMFIP_NODATA
Design diagram
The following diagram shows a simplified view of the libMilterPHP implementation.
+----------------+ +-------------------+
| | | |
| common.inc.php | +---+-> | constants.inc.php |
| | | | |
+----------------+ | +-------------------+
|
Constants | Set system constants
Autoloader | Set milter protocol constants
Initialize logging |
|
| +----------------------------------------+
| | |
+-> | NoumeniaLibMilterPHPAutoloader.inc.php |
| | |
| +----------------------------------------+
|
| Define the autoloader function
|
| +-----------------+ use
| | | <-----> libLoggerPHP\Log
+-> | loginit.inc.php | <-----> libLoggerPHP\LogDestinationNull
| | <-----> libLoggerPHP\LogDestinationSyslog
+-----------------+
Set log destination
Set message priority
+----------------+ extends
| | <-----> libSDManager\SocketManager
| Milter.inc.php |
| | use
+----------------+ +-----> +---------------------+
| |
__construct() | ReplyHelper.inc.php |
reply() | |
processChild() +---------------------+
replyAddRecipient()
replyDeleteRecipient()
replyAccept()
replyReplaceBodyChunk()
replyContinue()
replyDiscard()
replyAddHeader()
replyChangeHeader()
replyDeleteHeader()
replyProgress()
replyQuarantine()
replyReject()
replyTempFail()
replyReplyCode()
Related projects
- Aetolos - Virtual hosting at your... command line!
- guardian-milter - Multi-purpose security milter.
- bravos - Log file security parser.
- mmDbDaemon is a memory-resident MaxMind Database reader implementation in PHP.
- libMilterPHP is a Postfix/Sendmail Milter library implementation in PHP.
- libSDManagerPHP provides a portable daemon with a Sockets and Streams manager.
- libLoggerPHP is a logging library implementation in PHP.
noumenia/libmilterphp 适用场景与选型建议
noumenia/libmilterphp 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 108 次下载、GitHub Stars 达 2, 最近一次更新时间为 2022 年 12 月 08 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「postfix」 「milter」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 noumenia/libmilterphp 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 noumenia/libmilterphp 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 noumenia/libmilterphp 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
PHP Mail Log Parser Library
ViMdAdmin :: Virtual Mailbox Administration
an implementation of postfix virtual users
Set of tools for Roundcube webmail
Alfabank REST API integration
windwork mailer component,Windwork 发邮件组件
统计信息
- 总下载量: 108
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 19
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: GPL-3.0-only
- 更新时间: 2022-12-08