192 lines
6.1 KiB
PHP
192 lines
6.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
$GLOBALS['feca_test_actions'] = [];
|
|
$GLOBALS['feca_test_mailer'] = null;
|
|
$GLOBALS['feca_test_last_mail'] = null;
|
|
|
|
if (!function_exists('add_action')) {
|
|
function add_action(string $hook, callable $callback): void
|
|
{
|
|
$GLOBALS['feca_test_actions'][$hook][] = $callback;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('remove_action')) {
|
|
function remove_action(string $hook, callable $callback): void
|
|
{
|
|
if (!isset($GLOBALS['feca_test_actions'][$hook])) {
|
|
return;
|
|
}
|
|
$GLOBALS['feca_test_actions'][$hook] = array_values(array_filter(
|
|
$GLOBALS['feca_test_actions'][$hook],
|
|
static fn(callable $registered): bool => $registered !== $callback
|
|
));
|
|
}
|
|
}
|
|
|
|
if (!function_exists('wp_mail')) {
|
|
function wp_mail($to, string $subject, string $message, $headers = '', $attachments = []): bool
|
|
{
|
|
$mailer = new FecaTestMailer();
|
|
foreach ($GLOBALS['feca_test_actions']['phpmailer_init'] ?? [] as $callback) {
|
|
$callback($mailer);
|
|
}
|
|
|
|
$headersList = is_array($headers) ? $headers : preg_split('/\r\n|\r|\n/', (string) $headers);
|
|
foreach ($headersList ?: [] as $header) {
|
|
$header = trim((string) $header);
|
|
if (stripos($header, 'Bcc:') === 0) {
|
|
$mailer->bcc[] = trim(substr($header, 4));
|
|
}
|
|
if (stripos($header, 'Cc:') === 0) {
|
|
$mailer->cc[] = trim(substr($header, 3));
|
|
}
|
|
}
|
|
|
|
$mailer->to = is_array($to) ? array_values($to) : [(string) $to];
|
|
$mailer->Subject = $subject;
|
|
$mailer->Body = $message;
|
|
$mailer->sentMime = "Date: Fri, 26 Jun 2026 10:00:00 +0000\r\n"
|
|
. "Message-ID: <fixture@example.org>\r\n"
|
|
. "To: " . implode(', ', $mailer->to) . "\r\n"
|
|
. "Cc: " . implode(', ', $mailer->cc) . "\r\n"
|
|
. "Subject: " . $subject . "\r\n\r\n"
|
|
. $message;
|
|
|
|
$GLOBALS['feca_test_mailer'] = $mailer;
|
|
$GLOBALS['feca_test_last_mail'] = [
|
|
'to' => $to,
|
|
'subject' => $subject,
|
|
'message' => $message,
|
|
'headers' => $headers,
|
|
'attachments' => $attachments,
|
|
];
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
final class FecaTestMailer
|
|
{
|
|
public string $Host = '';
|
|
public int $Port = 0;
|
|
public bool $SMTPAuth = false;
|
|
public string $Username = '';
|
|
public string $Password = '';
|
|
public string $Helo = '';
|
|
public string $CharSet = '';
|
|
public string $SMTPSecure = '';
|
|
public string $MessageID = '';
|
|
public bool $SMTPAutoTLS = false;
|
|
public string $ErrorInfo = '';
|
|
public string $Subject = '';
|
|
public string $Body = '';
|
|
public string $sentMime = '';
|
|
/** @var list<string> */
|
|
public array $to = [];
|
|
/** @var list<string> */
|
|
public array $cc = [];
|
|
/** @var list<string> */
|
|
public array $bcc = [];
|
|
/** @var list<array{bytes:string,filename:string,encoding:string,mime_type:string}> */
|
|
public array $stringAttachments = [];
|
|
|
|
public function isSMTP(): void
|
|
{
|
|
}
|
|
|
|
public function setFrom(string $address, string $name = '', bool $auto = true): void
|
|
{
|
|
}
|
|
|
|
public function addStringAttachment(string $bytes, string $filename, string $encoding, string $mimeType): void
|
|
{
|
|
$this->stringAttachments[] = [
|
|
'bytes' => $bytes,
|
|
'filename' => $filename,
|
|
'encoding' => $encoding,
|
|
'mime_type' => $mimeType,
|
|
];
|
|
}
|
|
|
|
public function getSentMIMEMessage(): string
|
|
{
|
|
return $this->sentMime;
|
|
}
|
|
}
|
|
|
|
require_once dirname(__DIR__, 2) . '/feca_mailshots_plugin/src/autoload.php';
|
|
|
|
use FecaMailshots\Infrastructure\WordPressSmtpSender;
|
|
|
|
$sender = new WordPressSmtpSender();
|
|
$binaryPdfBytes = "%PDF-1.7\n" . "\x00\x01\x80\xff" . "\n%%EOF";
|
|
$result = $sender->send(
|
|
[
|
|
'smtp_host' => 'smtp.example.org',
|
|
'smtp_port' => 587,
|
|
'smtp_user' => 'editor@example.org',
|
|
'smtp_password' => 'secret',
|
|
'smtp_from_email' => 'Editor@Example.ORG',
|
|
'smtp_from_name' => 'Editor',
|
|
'smtp_require_tls' => false,
|
|
],
|
|
['to@example.org'],
|
|
['copy@example.org'],
|
|
['hidden@example.org'],
|
|
'Subject',
|
|
'<p>Hello</p>',
|
|
'reply@example.org',
|
|
[[
|
|
'filename' => 'notice.pdf',
|
|
'mime_type' => 'application/pdf',
|
|
'content_bytes' => $binaryPdfBytes,
|
|
]]
|
|
);
|
|
|
|
$mailer = $GLOBALS['feca_test_mailer'];
|
|
if (!$mailer instanceof FecaTestMailer) {
|
|
fwrite(STDERR, "WordPress mailer was not configured\n");
|
|
exit(1);
|
|
}
|
|
if ($mailer->Host !== 'smtp.example.org' || $mailer->Port !== 587 || $mailer->Username !== 'editor@example.org') {
|
|
fwrite(STDERR, "SMTP credentials were not applied to WordPress mailer\n");
|
|
exit(1);
|
|
}
|
|
if ($mailer->Helo !== 'example.org') {
|
|
fwrite(STDERR, "SMTP EHLO domain should be derived from From email\n");
|
|
exit(1);
|
|
}
|
|
if (preg_match('/^<\\d{14}\\.[a-f0-9]{32}@example\\.org>$/', $mailer->MessageID) !== 1) {
|
|
fwrite(STDERR, "Message-ID should be generated with the From email domain\n");
|
|
exit(1);
|
|
}
|
|
if ($mailer->bcc !== ['hidden@example.org']) {
|
|
fwrite(STDERR, "BCC recipients should still be delivered through WordPress mail\n");
|
|
exit(1);
|
|
}
|
|
if (preg_match('/^Bcc:/mi', (string) $result['raw_mime']) === 1) {
|
|
fwrite(STDERR, "Raw MIME should not expose Bcc header\n");
|
|
exit(1);
|
|
}
|
|
if ($mailer->stringAttachments === [] || $mailer->stringAttachments[0]['filename'] !== 'notice.pdf') {
|
|
fwrite(STDERR, "In-memory attachment was not added to WordPress mailer\n");
|
|
exit(1);
|
|
}
|
|
if (($mailer->stringAttachments[0]['bytes'] ?? '') !== $binaryPdfBytes) {
|
|
fwrite(STDERR, "Binary attachment bytes should be passed to PHPMailer unchanged\n");
|
|
exit(1);
|
|
}
|
|
if (($GLOBALS['feca_test_actions']['phpmailer_init'] ?? []) !== []) {
|
|
fwrite(STDERR, "phpmailer_init hook should be removed after send\n");
|
|
exit(1);
|
|
}
|
|
if (strpos((string) $result['raw_mime'], 'Message-ID: <fixture@example.org>') === false) {
|
|
fwrite(STDERR, "Raw MIME from WordPress mailer was not returned\n");
|
|
exit(1);
|
|
}
|
|
|
|
echo "WordPressSmtpSender regression test passed\n";
|