mlocati / spf-lib
解析、构建和验证 SPF (发送者策略框架) DNS 记录
Requires
- php: >=7.1.0
- mlocati/idna: ^1
- mlocati/ip-lib: ^1.11
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16
- phpunit/phpunit: ^7.5 || ^8.5 || ^9.4
- symfony/yaml: ^4.4 || ^5.1
README
SPF (发送者策略框架) 库
此 PHP 库允许您
- 从域名获取 SPF 记录
- 解码和验证 SPF 记录
- 创建 TXT 记录的值
- 检查域名和 IP 地址是否满足 SPF 记录
实现基于 RFC 7208。
据我所知,这是唯一通过 Open SPF 测试套件(针对 RFC 7208) 的 PHP 库。
此库支持从 PHP 7.1 到 8.3 的任何 PHP 版本。
关于 SPF 的简要介绍
以下是 SPF 协议目的的非常简化的简要描述。
当电子邮件客户端联系电子邮件服务器以发送电子邮件消息时,电子邮件服务器有这些信息
- 发送电子邮件的电子邮件客户端的 IP 地址
- 电子邮件客户端在 SMTP 交付开始时指定的域名(在
HELO
/EHLO
SMTP 命令之后) - 发送者电子邮件地址(在
MAIL FROM
SMTP 命令中指定)
电子邮件服务器可以使用 SPF 协议来确定客户端是否被允许或被拒绝使用指定的域名发送电子邮件(HELO
/EHLO
域和/或 MAIL FROM
电子邮件地址中 @
之后)。
这是通过查询要检查的域名(域)的 SPF DNS 记录来完成的,这些记录可以告诉服务器客户端是否被允许/不允许/很可能不被允许发送电子邮件。
您可以使用此 PHP 库构建、验证和检查 SPF 记录。
安装
您可以使用 Composer 安装此库
composer require mlocati/spf-lib
用法
验证域名和 IP 地址
假设电子邮件客户端具有 IP 地址 1.2.3.4
,使用 HELO
/EHLO
SMTP 命令指定 helo.domain
,并在 MAIL FROM
电子邮件地址中指定 [email protected]
。
这些数据由 SPFLib\Check\Environment
类表示:您可以使用以下方式创建它
$environment = new \SPFLib\Check\Environment(`1.2.3.4`, `helo.domain`, `[email protected]`);
要检查 SPF 记录,您可以使用 SPFLib\Checker
类
$checker = new \SPFLib\Checker(); $checkResult = $checker->check($environment);
默认情况下,check()
方法检查 HELO
/EHLO
和 MAIL FROM
域(如果都可用且不同)。您可以通过将 \SPFLib\Checker::FLAG_CHECK_HELODOMAIN
或 \SPFLib\Checker::FLAG_CHECK_MAILFROADDRESS
作为 check()
方法的第二个参数指定,仅检查其中一个。否则,您可以在相关的 Environment
构造函数中指定一个空字符串(例如:new Environment($ip, $domain)
将仅检查 HELO
/EHLO
域,new Environment($ip, '', $mailFromAddress)
将仅检查 MAIL FROM
电子邮件地址的域名)。
$checkResult
是 SPFLib\Term\Mechanism\Result
的一个实例,它提供
- 检查结果(
$checkResult->getCode()
),这是在 RFC 中指定的 值之一。 - 如果有的话,提供结果的 SPF 机制(
$checkResult->getMatchedMechanism()
) - 失败描述,如果由 SPF 记录提供(
$checkResult->getFailExplanation()
) - 检查过程中的可选相关消息(
$checkResult->getMessages()
)
因此,最简单的例子是
use SPFLib\Checker; use SPFLib\Check\Environment; $checker = new Checker(); $checkResult = $checker->check(new Environment('127.0.0.1', 'gmail.com')); echo $checkResult->getCode();
它将输出
softfail
从域名检索 SPF 记录
SPF 记录由零个或多个术语组成。每个术语可以是机制或修饰符。
此库允许您检查它们
$decoder = new \SPFLib\Decoder(); try { $record = $decoder->getRecordFromDomain('example.com'); } catch (\SPFLib\Exception $x) { // Problems retrieving the SPF record from example.com, // or problems decoding it return; } if ($record === null) { // SPF record not found for example.com return; } // List all terms (that is, mechanisms and modifiers) foreach ($record->getTerms() as $term) { // do your stuff } // List all mechanisms foreach ($record->getMechanisms() as $mechanism) { // do your stuff } // List all modifiers foreach ($record->getModifiers() as $modifiers) { // do your stuff }
请注意
- 所有 机制 都扩展了
SPFLib\Term\Mechanism
抽象类。 - 所有 修饰符 都扩展了
SPFLib\Term\Modifier
抽象类。 - 机制和修饰符都实现了
SPFLib\Term
接口。
从 TXT DNS 记录的值解码 SPF 记录
$txtRecord = 'v=spf1 mx a -all'; $decoder = new \SPFLib\Decoder(); try { $record = $decoder->getRecordFromTXT($txtRecord); } catch (\SPFLib\Exception $x) { // Problems decoding $txtRecord (it's malformed). return; } if ($record === null) { // $txtRecord is not an SPF record return; }
创建 SPF 记录的值
use SPFLib\Term\Mechanism; $record = new \SPFLib\Record('example.org'); $record ->addTerm(new Mechanism\MxMechanism(Mechanism::QUALIFIER_PASS)) ->addTerm(new Mechanism\IncludeMechanism(Mechanism::QUALIFIER_PASS, 'example.com')) ->addTerm(new Mechanism\AllMechanism(Mechanism::QUALIFIER_FAIL)) ; echo (string) $record;
输出
v=spf1 mx include:example.com -all
检查 SPF 记录的问题
$spf = 'v=spf1 all redirect=example1.org redirect=example2.org ptr:foo.bar mx include=example3.org exp=test.%{p}'; $record = (new \SPFLib\Decoder())->getRecordFromTXT($spf); $issues = (new \SPFLib\SemanticValidator())->validate($record); foreach ($issues as $issue) { echo (string) $issue, "\n"; }
输出
[warning] 'all' should be the last mechanism (any other mechanism will be ignored)
[warning] The 'redirect' modifier will be ignored since there's a 'all' mechanism
[notice] The 'ptr' mechanism shouldn't be used because it's slow, resource intensive, and not very reliable
[notice] The term 'exp=test.%{p}' contains the macro-letter 'p' that shouldn't be used because it's slow, resource intensive, and not very reliable
[notice] The modifiers ('redirect=example1.org', 'redirect=example2.org') should be after all the mechanisms
[fatal] The 'redirect' modifier is present more than once (2 times)
[notice] The 'include=example3.org' modifier is unknown
请注意,validate
方法返回的数组中的每个项目都是 SPFLib\Semantic\Issue
类的实例。
在现实世界中检查 SPF 记录的问题
SemanticValidator
只在 SPF 记录中查找问题,而不检查 include(或重定向到)记录。
为了检查 SPF 记录及其所有引用的记录,您可以使用 OnlineSemanticValidator
$validator = new \SPFLib\OnlineSemanticValidator(); // Check an online domain $issues = $validator->validateDomain('example.org'); // Check a raw SPF record $issues = $validator->validateRawRecord('v=spf1 include:_sfp.example.org -all'); // Check an SPFLib\Record instance ($record in this case) $issues = $validator->validateRecord($record);
这些方法的结果是 SPFLib\Semantic\OnlineIssue
实例的数组,这些实例与离线 SemanticValidator
返回的 SPFLib\Semantic\Issue
实例非常相似。