Follow-up to remove IMAP ext (#13248)

Fixed and optimized tests that depend on imap in standard ext tests.

Also, the location of the setup script for hmailserver has changed.
This commit is contained in:
Saki Takamachi 2024-02-09 21:32:07 +09:00 committed by GitHub
parent 3ce7bf2a77
commit f62f6a6d4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 636 additions and 1315 deletions

View File

@ -23,9 +23,3 @@ runs:
sudo cp ext/snmp/tests/snmpd.conf /etc/snmp
sudo cp ext/snmp/tests/bigtest /etc/snmp
sudo service snmpd restart
sudo groupadd -g 5000 vmail
sudo useradd -m -d /var/vmail -s /bin/false -u 5000 -g vmail vmail
sudo cp ext/imap/tests/setup/dovecot.conf /etc/dovecot/dovecot.conf
sudo cp ext/imap/tests/setup/dovecotpass /etc/dovecot/dovecotpass
sudo service dovecot restart

View File

@ -112,7 +112,7 @@ rem prepare for mail
curl -sLo hMailServer.exe https://www.hmailserver.com/download_file/?downloadid=271
hMailServer.exe /verysilent
cd %APPVEYOR_BUILD_FOLDER%
%PHP_BUILD_DIR%\php.exe -dextension_dir=%PHP_BUILD_DIR% -dextension=com_dotnet appveyor\setup_hmailserver.php
%PHP_BUILD_DIR%\php.exe -dextension_dir=%PHP_BUILD_DIR% -dextension=com_dotnet .github\setup_hmailserver.php
mkdir %PHP_BUILD_DIR%\test_file_cache
rem generate php.ini

View File

@ -1,21 +1,25 @@
<?php
require __DIR__ . "/../ext/imap/tests/setup/imap_include.inc";
$hmail = new COM("hMailServer.Application");
$hmail->authenticate("Administrator", "");
$domain = $hmail->Domains->Add();
$domain->Name = IMAP_MAIL_DOMAIN;
$domain->Active = true;
$domain->Save();
$accounts = $domain->accounts();
foreach (IMAP_USERS as $user) {
$account = $accounts->Add();
$account->Address = "$user@" . IMAP_MAIL_DOMAIN;
$account->Password = IMAP_MAILBOX_PASSWORD;
$account->Active = true;
$account->Save();
}
<?php
/** If required change these values to make the test runs */
const IMAP_MAIL_DOMAIN = 'example.com';
const IMAP_MAILBOX_PASSWORD = 'p4ssw0rd';
/** Tests require 4 valid userids */
const IMAP_USERS = ["webmaster", "info", "admin", "foo"];
$hmail = new COM("hMailServer.Application");
$hmail->authenticate("Administrator", "");
$domain = $hmail->Domains->Add();
$domain->Name = IMAP_MAIL_DOMAIN;
$domain->Active = true;
$domain->Save();
$accounts = $domain->accounts();
foreach (IMAP_USERS as $user) {
$account = $accounts->Add();
$account->Address = "$user@" . IMAP_MAIL_DOMAIN;
$account->Password = IMAP_MAILBOX_PASSWORD;
$account->Active = true;
$account->Save();
}

View File

@ -1,32 +0,0 @@
<?php
require_once 'imap_include.inc';
if (!isset($mailbox_suffix)) { throw new Exception("No suffix provided"); }
$imap_stream = imap_open(IMAP_DEFAULT_MAILBOX, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD);
// delete all msgs in default mailbox, i.e INBOX
$check = imap_check($imap_stream);
for ($i = 1; $i <= $check->Nmsgs; $i++) {
imap_delete($imap_stream, $i);
}
$mailboxes = imap_getmailboxes($imap_stream, IMAP_SERVER, '*');
if (!is_array($mailbox_suffix)) {
$mailbox_suffixes = [$mailbox_suffix];
} else {
$mailbox_suffixes = $mailbox_suffix;
}
foreach ($mailbox_suffixes as $mailbox_suffix) {
foreach($mailboxes as $value) {
// Only delete mailbox with our prefix (+ optional test suffix)
if (preg_match('/\{.*?\}INBOX\.' . IMAP_MAILBOX_PHPT_PREFIX . $mailbox_suffix .'$/', $value->name, $match) == 1) {
imap_deletemailbox($imap_stream, $value->name);
}
}
}
imap_close($imap_stream, CL_EXPUNGE);

View File

@ -1,47 +0,0 @@
# 2.2.33.2 (d6601f4ec): /etc/dovecot/dovecot.conf
# Pigeonhole version 0.4.21 (92477967)
listen = *, ::
# For SSL need to setup a certificate
# See https://wiki.dovecot.org/SSL/DovecotConfiguration
ssl = no
# Disable plaintext to prevent a warning at each login
disable_plaintext_auth = yes
auth_mechanisms = cram-md5
auth_username_format = %u
auth_verbose = yes
auth_debug = yes
auth_failure_delay = 1secs
# This need dovecot 2.3.12.
# login_proxy_timeout = 500milliseconds
# ^ This would allow to kill login processes early, but needs testing. So would use v instead
# login_proxy_timeout = 5s
# There is a 1 second delay between each reconnection attempt.
# https://doc.dovecot.org/settings/core/#login-proxy-max-reconnects
# This need dovecot 2.3.12.
# login_proxy_max_reconnects = 3
# Log config
log_path = /var/log/dovecot.log
# If not set, use the value from log_path
info_log_path = /var/log/dovecot-info.log
# If not set, use the value from info_log_path
debug_log_path = /var/log/dovecot-debug.log
## Mailbox locations and namespaces
mail_location = maildir:/var/vmail/dovecot/mail/%d/%n/Maildir
passdb {
args = scheme=cram-md5 /etc/dovecot/dovecotpass
driver = passwd-file
}
protocols = imap
service auth {
user = root
}
userdb {
args = /etc/dovecot/dovecotpass
driver = passwd-file
override_fields = home=/var/vmail/dovecot/mail/%d/%n
}

View File

@ -1 +0,0 @@
webmaster@example.com:{CRAM-MD5}be5f3177e9c7c06403272f25d983ba630df4ef40476b353bb3087a8401713451:vmail:vmail

View File

@ -1,213 +0,0 @@
<?php
/** If required change these values to make the test runs */
const IMAP_SERVER_NO_DEBUG = '{127.0.0.1:143/norsh}';
const IMAP_SERVER_DEBUG = '{127.0.0.1:143/debug/norsh}';
const IMAP_SERVER = IMAP_SERVER_DEBUG;
const IMAP_DEFAULT_MAILBOX = IMAP_SERVER . 'INBOX';
const IMAP_MAIL_DOMAIN = 'example.com';
const IMAP_ADMIN_USER = 'webmaster'; // a user with admin access
const IMAP_MAILBOX_USERNAME = IMAP_ADMIN_USER . '@' . IMAP_MAIL_DOMAIN;
const IMAP_MAILBOX_PASSWORD = 'p4ssw0rd';
const IMAP_MAILBOX_PHPT_PREFIX = 'phpttest';
/** Tests require 4 valid userids */
const IMAP_USERS = ["webmaster", "info", "admin", "foo"];
/** list of fields to expect */
const MANDATORY_OVERVIEW_FIELDS = [
'size',
'uid',
'msgno',
'recent',
'flagged',
'answered',
'deleted',
'seen',
'draft',
'udate',
];
// record test start time (used by displayOverviewFields())
$start_time = time();
/**
* Display all fields in an element from an imap_fetch_overview() response
*
* Special handling for 'udate', which will vary run-to-run; assumes an IMAP
* server with its clock synced to the current system, which is consistent with
* setup instructions in ext/imap/tests/README.md
*
* @param $resp
* @param string[] $fields
*/
function displayOverviewFields($resp, array $fields = MANDATORY_OVERVIEW_FIELDS) {
global $start_time;
foreach ($fields as $mf) {
$z = $resp->$mf;
if ($mf == 'udate') {
if (($z >= $start_time) && ($z <= time())) {
echo "$mf is OK\n";
} else {
echo "$mf is BAD ($z)\n";
}
} else {
echo "$mf is $z\n";
}
}
}
/**
* Create a test mailbox and populate with msgs
*
* @param string mailbox_suffix Suffix used to uniquely identify mailboxes
* @param int message_count number of test msgs to be written to new mailbox
* @param null $new_mailbox
* @param bool $simpleMessages
* @param int $flags OP_* (or CL_EXPUNGE) flags to pass to imap_open() sub-call
* @return resource IMAP stream to new mailbox
* @throws Exception
*/
function setup_test_mailbox(
string $mailbox_suffix,
int $message_count,
&$new_mailbox = null,
bool $simpleMessages = true,
int $flags = 0,
){
// open a stream to default mailbox
$imap_stream = imap_open(IMAP_DEFAULT_MAILBOX, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD, flags: $flags);
if ($imap_stream === false) {
throw new Exception("Cannot connect to IMAP server " . IMAP_SERVER . ": " . imap_last_error());
}
echo "Create a temporary mailbox and add " . $message_count . " msgs\n";
$new_mailbox = create_mailbox($imap_stream, $mailbox_suffix, $message_count, $simpleMessages);
echo "New mailbox created\n";
// reopen stream to new mailbox
if (imap_reopen($imap_stream, $new_mailbox) === false) {
throw new Exception("Can't re-open '$new_mailbox' mailbox: " . imap_last_error());
}
return $imap_stream;
}
/**
* Create mailbox and fill with generic emails
*
* @param resource $imap_stream
* @param string $mailbox_suffix
* @param int $message_count
* @param bool $simpleMessages
* @return string
* @throws Exception
*/
function create_mailbox($imap_stream, string $mailbox_suffix, int $message_count, bool $simpleMessages = true): string {
$mailbox = IMAP_DEFAULT_MAILBOX . '.' . IMAP_MAILBOX_PHPT_PREFIX . $mailbox_suffix;
$mailboxes = imap_getmailboxes($imap_stream, $mailbox, '*');
// check mailbox does not already exist
if ($mailboxes) {
foreach($mailboxes as $value) {
if ($value->name == $mailbox) {
throw new Exception("Mailbox '$mailbox' already exists");
}
}
}
if (imap_createmailbox($imap_stream, $mailbox) === false) {
throw new Exception("Can't create a temporary mailbox: " . imap_last_error());
}
// Add number of test msgs requested
if ($message_count > 0) {
populate_mailbox($imap_stream, $mailbox, $message_count, $simpleMessages);
}
return $mailbox;
}
function setup_test_mailbox_for_uid_tests(string $mailbox_suffix, &$msg_no = null, &$msg_uid = null)
{
$mail_box = setup_test_mailbox($mailbox_suffix, 10);
echo "Delete 4 messages for Unique ID generation\n";
// Delete messages to remove the numerical ordering
imap_delete($mail_box, 3);
imap_delete($mail_box, 4);
imap_delete($mail_box, 5);
imap_delete($mail_box, 6);
imap_expunge($mail_box);
$msg_no = 5;
$msg_uid = 9;
return $mail_box;
}
/**
* Populate a mailbox with generic emails
*
* @param resource $imap_stream
* @param string $mailbox
* @param int $message_count
* @param bool $simpleMessages
*/
function populate_mailbox($imap_stream, string $mailbox, int $message_count, bool $simpleMessages = true): void {
for ($i = 1; $i <= $message_count; $i++) {
if ($simpleMessages) {
$msg = "From: foo@anywhere.com\r\n"
. "To: ". IMAP_USERS[0] . "@" . IMAP_MAIL_DOMAIN . "\r\n"
. "Subject: test$i\r\n"
. "\r\n"
. "$i: this is a test message, please ignore\r\nnewline";
} else {
$envelope["from"]= "foo@anywhere.com";
$envelope["to"] = IMAP_USERS[0] . "@" . IMAP_MAIL_DOMAIN;
$envelope["subject"] = "Test msg $i";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPETEXT;
$part2["subtype"] = "plain";
$part2["description"] = "imap_mail_compose() function";
$part2["contents.data"] = "message 1:xxxxxxxxxxxxxxxxxxxxxxxxxx";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "Example";
$part3["contents.data"] = "message 2:yyyyyyyyyyyyyyyyyyyyyyyyyy";
$part4["type"] = TYPETEXT;
$part4["subtype"] = "plain";
$part4["description"] = "Return Values";
$part4["contents.data"] = "message 3:zzzzzzzzzzzzzzzzzzzzzzzzzz";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
$body[4] = $part4;
$msg = imap_mail_compose($envelope, $body);
}
imap_append($imap_stream, $mailbox, $msg);
}
}
/**
* Get the mailbox name from a mailbox description, i.e strip off server details.
*
* @param string mailbox complete mailbox name
* @return string mailbox name
*/
function get_mailbox_name(string $mailboxName): string {
if (preg_match('/\{.*?\}(.*)/', $mailboxName, $match) != 1) {
throw new Exception("Unrecognized mailbox name '$mailboxName'");
}
return $match[1];
}

View File

@ -1,6 +0,0 @@
sudo service dovecot stop
sudo groupadd -g 5000 vmail
sudo useradd -m -d /var/vmail -s /bin/false -u 5000 -g vmail vmail
sudo cp ext/imap/tests/setup/dovecot.conf /etc/dovecot/dovecot.conf
sudo cp ext/imap/tests/setup/dovecotpass /etc/dovecot/dovecotpass
sudo service dovecot start

View File

@ -1,11 +0,0 @@
<?php
include __DIR__ . '/imap_include.inc';
$options = OP_HALFOPEN; // this should be enough to verify server present
$retries = 0; // don't retry connect on failure
$mbox = @imap_open(IMAP_SERVER, IMAP_MAILBOX_USERNAME, IMAP_MAILBOX_PASSWORD, $options, $retries);
if (!$mbox) {
die("skip could not connect to mailbox " . IMAP_SERVER);
}
imap_close($mbox);

View File

@ -1,77 +1,64 @@
--TEST--
Bug #72964 (White space not unfolded for CC/Bcc headers)
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only test');
if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
require_once __DIR__ . '/mail_skipif.inc';
require_once __DIR__.'/mail_windows_skipif.inc';
?>
--INI--
SMTP=localhost
smtp_port=25
sendmail_from=from@example.com
--FILE--
<?php
require_once __DIR__ . '/mail_include.inc';
function find_and_delete_message($username, $subject) {
global $default_mailbox, $password;
require_once __DIR__.'/mail_util.inc';
$users = MailBox::USERS;
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
die("Cannot connect to IMAP server $server: " . imap_last_error() . "\n");
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$num_messages = imap_check($imap_stream)->Nmsgs;
for ($i = $num_messages; $i > 0; $i--) {
$info = imap_headerinfo($imap_stream, $i);
if ($info->subject === $subject) {
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count--;
}
imap_close($imap_stream, CL_EXPUNGE);
return $found;
}
$to = "{$users[2]}@$domain";
$subject = bin2hex(random_bytes(16));
$to = $users[0];
$from = ini_get('sendmail_from');
$cc = ['cc1' => $users[0], 'cc2' => $users[1]];
$bcc = ['bcc1' => $users[2], 'bcc2' => $users[3]];
$subject = 'mail_bug72964';
$message = 'hello';
$headers = "From: webmaster@example.com\r\n"
. "Cc: {$users[0]}@$domain,\r\n\t{$users[1]}@$domain\r\n"
. "Bcc: {$users[2]}@$domain,\r\n {$users[3]}@$domain\r\n";
$headers = "From: {$from}\r\n"
. "Cc: {$cc['cc1']},\r\n\t{$cc['cc2']}\r\n"
. "Bcc: {$bcc['bcc1']},\r\n {$bcc['bcc2']}\r\n";
$res = mail($to, $subject, $message, $headers);
if ($res !== true) {
die("TEST FAILED : Unable to send test email\n");
} else {
echo "Message sent OK\n";
die("Unable to send the email.\n");
}
foreach ($users as $user) {
if (!find_and_delete_message("$user@$domain", $subject)) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Message sent and deleted OK\n";
echo "Email sent.\n";
foreach ([['to' => $to], $cc, $bcc] as $mailAddresses) {
foreach ($mailAddresses as $recipient => $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mail = $mailBox->getMailsBySubject($subject);
$mailBox->logout();
if ($mail->isAsExpected($from, $to, $subject, $message)) {
echo "Found the email. {$recipient} received.\n";
}
}
}
?>
--CLEAN--
<?php
require_once __DIR__.'/mail_util.inc';
$subject = 'mail_bug72964';
foreach (MailBox::USERS as $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mailBox->deleteMailsBySubject($subject);
$mailBox->logout();
}
?>
--EXPECT--
Message sent OK
TEST PASSED: Message sent and deleted OK
TEST PASSED: Message sent and deleted OK
TEST PASSED: Message sent and deleted OK
TEST PASSED: Message sent and deleted OK
Email sent.
Found the email. to received.
Found the email. cc1 received.
Found the email. cc2 received.
Found the email. bcc1 received.
Found the email. bcc2 received.

View File

@ -1,80 +1,66 @@
--TEST--
Bug #72964 (White space not unfolded for CC/Bcc headers)
--EXTENSIONS--
imap
--CONFLICTS--
imap
Bug #80706 (Headers after Bcc headers may be ignored)
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only test');
if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
require_once __DIR__ . '/mail_skipif.inc';
require_once __DIR__.'/mail_windows_skipif.inc';
?>
--INI--
SMTP=localhost
smtp_port=25
sendmail_from=from@example.com
--FILE--
<?php
require_once __DIR__ . '/mail_include.inc';
function find_and_delete_message($username, $subject) {
global $default_mailbox, $password;
require_once __DIR__.'/mail_util.inc';
$users = MailBox::USERS;
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
die("Cannot connect to IMAP server $server: " . imap_last_error() . "\n");
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$num_messages = imap_check($imap_stream)->Nmsgs;
for ($i = $num_messages; $i > 0; $i--) {
$info = imap_headerinfo($imap_stream, $i);
if ($info->subject === $subject) {
$header = imap_fetchheader($imap_stream, $i);
echo "X-Mailer header found: ";
var_dump(strpos($header, 'X-Mailer: bug80706') !== false);
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count--;
}
imap_close($imap_stream, CL_EXPUNGE);
return $found;
}
$to = "{$users[1]}@$domain";
$subject = bin2hex(random_bytes(16));
$to = $users[0];
$from = ini_get('sendmail_from');
$bcc = $users[2];
$subject = 'mail_bug80706';
$message = 'hello';
$headers = "From: webmaster@example.com\r\n"
. "Bcc: {$users[2]}@$domain\r\n"
. "X-Mailer: bug80706";
$xMailer = 'bug80706_x_mailer';
$headers = "From: {$from}\r\n"
. "Bcc: {$bcc}\r\n"
. "X-Mailer: {$xMailer}";
$res = mail($to, $subject, $message, $headers);
if ($res !== true) {
die("TEST FAILED : Unable to send test email\n");
} else {
echo "Message sent OK\n";
die("Unable to send the email.\n");
}
foreach ([$users[1], $users[2]] as $user) {
if (!find_and_delete_message("$user@$domain", $subject)) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Message sent and deleted OK\n";
echo "Email sent.\n";
foreach (['to' => $to, 'bcc' => $bcc] as $recipient => $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mail = $mailBox->getMailsBySubject($subject);
$mailBox->logout();
if ($mail->isAsExpected($from, $to, $subject, $message)) {
echo "Found the email. {$recipient} received.\n";
}
if ($mail->getHeader('X-Mailer') === $xMailer) {
echo "The specified x-Mailer exists.\n\n";
}
}
?>
--CLEAN--
<?php
require_once __DIR__.'/mail_util.inc';
$subject = 'mail_bug80706';
foreach ([MailBox::USERS[0], MailBox::USERS[2]] as $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mailBox->deleteMailsBySubject($subject);
$mailBox->logout();
}
?>
--EXPECT--
Message sent OK
X-Mailer header found: bool(true)
TEST PASSED: Message sent and deleted OK
X-Mailer header found: bool(true)
TEST PASSED: Message sent and deleted OK
Email sent.
Found the email. to received.
The specified x-Mailer exists.
Found the email. bcc received.
The specified x-Mailer exists.

View File

@ -1,97 +1,82 @@
--TEST--
Bug #80751 (Comma in recipient name breaks email delivery)
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only test');
if (getenv("SKIP_SLOW_TESTS")) die('skip slow test');
require_once __DIR__ . '/mail_skipif.inc';
require_once __DIR__.'/mail_windows_skipif.inc';
?>
--INI--
SMTP=localhost
smtp_port=25
--FILE--
<?php
require_once __DIR__ . '/mail_include.inc';
function find_and_delete_message($username, $subject) {
global $default_mailbox, $password, $users, $domain;
require_once __DIR__.'/mail_util.inc';
$users = MailBox::USERS;
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
die("Cannot connect to IMAP server $server: " . imap_last_error() . "\n");
}
$to = $users[0];
$toLine = "\"<bug80751_to_name@example.com>\" <{$to}>";
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$num_messages = imap_check($imap_stream)->Nmsgs;
for ($i = $num_messages; $i > 0; $i--) {
$info = imap_headerinfo($imap_stream, $i);
if ($info->subject === $subject) {
$header = imap_fetchheader($imap_stream, $i);
echo "Return-Path header found: ";
var_dump(strpos($header, 'Return-Path: joe@example.com') !== false);
echo "To header found: ";
var_dump(strpos($header, "To: \"<bob@example.com>\" <{$users[1]}@$domain>") !== false);
echo "From header found: ";
var_dump(strpos($header, 'From: "<bob@example.com>" <joe@example.com>') !== false);
echo "Cc header found: ";
var_dump(strpos($header, "Cc: \"Lastname, Firstname\\\\\" <{$users[2]}@$domain>") !== false);
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count--;
}
$from = 'bug80751_from@example.com';
$fromLine = "\"<bug80751_from_name@example.com>\" <{$from}>";
imap_close($imap_stream, CL_EXPUNGE);
return $found;
}
$cc = $users[1];
$ccLine = "\"Lastname, Firstname\\\\\" <{$cc}>";
$to = "\"<bob@example.com>\" <{$users[1]}@$domain>";
$subject = bin2hex(random_bytes(16));
$bcc = $users[2];
$subject = 'mail_bug80751';
$message = 'hello';
$headers = "From: \"<bob@example.com>\" <joe@example.com>\r\n"
. "Cc: \"Lastname, Firstname\\\\\" <{$users[2]}@$domain>\r\n"
. "Bcc: \"Firstname \\\"Ni,ck\\\" Lastname\" <{$users[3]}@$domain>\r\n";
$res = mail($to, $subject, $message, $headers);
$headers = "From: {$fromLine}\r\n"
. "Cc: {$ccLine}\r\n"
. "Bcc: \"Firstname \\\"Ni,ck\\\" Lastname\" <{$bcc}>\r\n";
$res = mail($toLine, $subject, $message, $headers);
if ($res !== true) {
die("TEST FAILED : Unable to send test email\n");
} else {
echo "Message sent OK\n";
die("Unable to send the email.\n");
}
foreach ([$users[1], $users[2], $users[3]] as $user) {
if (!find_and_delete_message("$user@$domain", $subject)) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Message sent and deleted OK\n";
echo "Email sent.\n";
foreach (['to' => $to, 'cc' => $cc, 'bcc' => $bcc] as $recipient => $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mail = $mailBox->getMailsBySubject($subject);
$mailBox->logout();
if ($mail->isAsExpected($fromLine, $toLine, $subject, $message)) {
echo "Found the email. {$recipient} received.\n";
}
if ($mail->getHeader('Return-Path') === $from) {
echo "Return-Path is as expected.\n";
}
if ($mail->getHeader('Cc') === $ccLine) {
echo "Cc header is as expected.\n\n";
}
}
?>
--CLEAN--
<?php
require_once __DIR__.'/mail_util.inc';
$subject = 'mail_bug80751';
foreach ([MailBox::USERS[0], MailBox::USERS[1], MailBox::USERS[2]] as $mailAddress) {
$mailBox = MailBox::login($mailAddress);
$mailBox->deleteMailsBySubject($subject);
$mailBox->logout();
}
?>
--EXPECT--
Message sent OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
Return-Path header found: bool(true)
To header found: bool(true)
From header found: bool(true)
Cc header found: bool(true)
TEST PASSED: Message sent and deleted OK
Email sent.
Found the email. to received.
Return-Path is as expected.
Cc header is as expected.
Found the email. cc received.
Return-Path is as expected.
Cc header is as expected.
Found the email. bcc received.
Return-Path is as expected.
Cc header is as expected.

View File

@ -1,90 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
ini_set("SMTP", "localhost");
ini_set("smtp_port", 25);
ini_set("sendmail_from", "user@example.com");
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = mail($to, $subject, $message);
if ($res !== true) {
exit("TEST FAILED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
--EXPECTF--
*** Testing mail() : basic functionality ***
Msg sent OK
Id of msg just sent is %d
.. delete it
TEST PASSED: Msgs sent and deleted OK

View File

@ -1,87 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$extra_headers = "from: user@example.com";
$res = mail($to, $subject, $message, $extra_headers);
if ($res !== true) {
exit("TEST FAILED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
--EXPECTF--
*** Testing mail() : basic functionality ***
Msg sent OK
Id of msg just sent is %d
.. delete it
TEST PASSED: Msgs sent and deleted OK

View File

@ -1,87 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$extra_headers = "FRom: user@example.com";
$res = mail($to, $subject, $message, $extra_headers);
if ($res !== true) {
exit("TEST FAILED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
--EXPECTF--
*** Testing mail() : basic functionality ***
Msg sent OK
Id of msg just sent is %d
.. delete it
TEST PASSED: Msgs sent and deleted OK

View File

@ -1,88 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$extra_headers = "from: user@example.com";
$extra_parameters = "addons"; // should be ignored
$res = mail($to, $subject, $message, $extra_headers, $extra_parameters);
if ($res !== true) {
exit("TEST FAILED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
--EXPECTF--
*** Testing mail() : basic functionality ***
Msg sent OK
Id of msg just sent is %d
.. delete it
TEST PASSED: Msgs sent and deleted OK

View File

@ -0,0 +1,102 @@
--TEST--
Test mail() function : basic functionality (win)
--SKIPIF--
<?php require_once __DIR__.'/mail_windows_skipif.inc'; ?>
--INI--
SMTP=localhost
smtp_port=25
--FILE--
<?php
require_once __DIR__.'/mail_util.inc';
$users = MailBox::USERS;
$cases = [
[
'from' => 'from@example.com',
'premise' => function ($from, $to, $subject, $message) {
ini_set('sendmail_from', $from);
return mail($to, $subject, $message);
}
],
[
'from' => 'ex_from@example.com',
'premise' => function ($from, $to, $subject, $message) {
ini_restore('sendmail_from');
$headers = "from: {$from}";
return mail($to, $subject, $message, $headers);
}
],
[
'from' => 'ex_from@example.com',
'premise' => function ($from, $to, $subject, $message) {
ini_restore('sendmail_from');
$headers = "FRom: {$from}";
return mail($to, $subject, $message, $headers);
}
],
[
'from' => 'ex_from@example.com',
'premise' => function ($from, $to, $subject, $message) {
ini_restore('sendmail_from');
$headers = "from: {$from}";
$parameters = 'addons'; // should be ignored
return mail($to, $subject, $message, $headers, $parameters);
}
],
];
foreach ($cases as $index => ['from' => $from, 'premise' => $premise]) {
echo "========== Case {$index} ==========\n";
$to = $users[$index];
$subject = "{$index}: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = $premise($from, $to, $subject, $message);
if ($res !== true) {
die("Unable to send the email.\n");
}
echo "Email sent.\n";
$mailBox = MailBox::login($to);
$mail = $mailBox->getMailsBySubject($subject);
$mailBox->logout();
if ($mail->isAsExpected($from, $to, $subject, $message)) {
echo "Found the email.\n\n";
}
}
?>
--CLEAN--
<?php
require_once __DIR__.'/mail_util.inc';
for ($i = 0; $i <= 3; $i++) {
$subject = "{$i}: Basic PHPT test for mail() function";
$mailBox = MailBox::login(MailBox::USERS[$i]);
$mailBox->deleteMailsBySubject($subject);
$mailBox->logout();
}
?>
--EXPECT--
========== Case 0 ==========
Email sent.
Found the email.
========== Case 1 ==========
Email sent.
Found the email.
========== Case 2 ==========
Email sent.
Found the email.
========== Case 3 ==========
Email sent.
Found the email.

View File

@ -1,150 +0,0 @@
<?php
// Change these to make tests run successfully
$server = '{127.0.0.1:143}';
$default_mailbox = $server . "INBOX";
$domain = "example.com";
$admin_user = "webmaster"; // a user with admin access
$username = "$admin_user@$domain";
$password = 'p4ssw0rd';
$users = array("webmaster", "info", "admin", "foo"); // tests require 4 valid userids
$mailbox_prefix = "phpttest"; // name used for test mailbox
/**
* Create a test mailbox and populate with msgs
*
* @para, string mailbox_suffix Suffix used to uniquely identify mailboxes
* @param int message_count number of test msgs to be written to new mailbox
*
* @return IMAP stream to new mailbox on success; FALSE on failure
*/
function setup_test_mailbox($mailbox_suffix, $message_count, &$new_mailbox = null, $msg_type = "simple"){
global $server, $default_mailbox, $username, $password;
// open a stream to default mailbox
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
echo "Create a temporary mailbox and add " . $message_count . " msgs\n";
$new_mailbox = create_mailbox($imap_stream, $mailbox_suffix, $message_count, $msg_type);
if ($new_mailbox === false) {
echo "Can't create a temporary mailbox: " . imap_last_error(). "\n";
return false;
}
echo ".. mailbox '$new_mailbox' created\n";
// reopen stream to new mailbox
if (imap_reopen($imap_stream, $new_mailbox) === false) {
echo "can't re-open '$new_mailbox' mailbox: " . imap_last_error() . "\n";
return false;
}
return $imap_stream;
}
/**
* Create mailbox and fill with generic emails
*
* @param resource $imap_stream
* @param string $mailbox
*/
function create_mailbox($imap_stream, $mailbox_suffix, $message_count, $msg_type= "simple"){
global $default_mailbox, $mailbox_prefix;
$mailbox = $default_mailbox . "." . $mailbox_prefix . $mailbox_suffix;
$mailboxes = imap_getmailboxes($imap_stream, $mailbox, '*');
// check mailbox does not already exist
if ($mailboxes) {
foreach($mailboxes as $value) {
if ($value->name == $mailbox) {
exit ("TEST FAILED : Mailbox '$mailbox' already exists\n");
}
}
}
if (imap_createmailbox($imap_stream, $mailbox) === false) {
return false;
}
// Add number of test msgs requested
if ($message_count > 0) {
populate_mailbox($imap_stream, $mailbox, $message_count, $msg_type);
}
return $mailbox;
}
/**
* Populate a mailbox with generic emails
*
* @param resource $imap_stream
* @param string $mailbox
*/
function populate_mailbox($imap_stream, $mailbox, $message_count, $msg_type = "simple"){
global $users, $domain;
for($i = 1; $i <= $message_count; $i++) {
if ($msg_type == "simple") {
$msg = "From: foo@anywhere.com\r\n"
. "To: $users[0]@$domain\r\n"
. "Subject: test$i\r\n"
. "\r\n"
. "$i: this is a test message, please ignore\r\n";
} else {
$envelope["from"]= "foo@anywhere.com";
$envelope["to"] = "$users[0]@$domain";
$envelope["subject"] = "Test msg $i";
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
$part2["type"] = TYPETEXT;
$part2["subtype"] = "plain";
$part2["description"] = "imap_mail_compose() function";
$part2["contents.data"] = "message 1:xxxxxxxxxxxxxxxxxxxxxxxxxx";
$part3["type"] = TYPETEXT;
$part3["subtype"] = "plain";
$part3["description"] = "Example";
$part3["contents.data"] = "message 2:yyyyyyyyyyyyyyyyyyyyyyyyyy";
$part4["type"] = TYPETEXT;
$part4["subtype"] = "plain";
$part4["description"] = "Return Values";
$part4["contents.data"] = "message 3:zzzzzzzzzzzzzzzzzzzzzzzzzz";
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
$body[4] = $part4;
$msg = imap_mail_compose($envelope, $body);
}
imap_append($imap_stream, $mailbox, $msg);
}
}
/**
* Get the mailbox name from a mailbox description, i.e strip off server details.
*
* @param string mailbox complete mailbox name
* @return mailbox name
*/
function get_mailbox_name($mailbox){
if (preg_match('/\{.*?\}(.*)/', $mailbox, $match) != 1) {
echo "Unrecpognized mailbox name\n";
return false;
}
return $match[1];
}
?>

View File

@ -1,25 +0,0 @@
<?php
if( substr(PHP_OS, 0, 3) == 'WIN' && extension_loaded('sockets')) {
// be sure mail server is accessible... on PHP 5.3.13 release build, using test-pack PHP-5.3-r1af8b3f,
// the code below didn't skip test even though there was no mail server
// test then failed (no mail server to test against)
$socket = socket_create(AF_INET, SOCK_RAW, 1);
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 10, 'usec' => 10));
// imap uses tcp port 143
socket_connect($socket, "localhost", 143) or die ("skip can't socket to mail server");
}
// Change these to make tests run successfully
$mailbox = '{127.0.0.1:143}';
$username = 'webmaster@example.com';
$password = 'p4ssw0rd';
$options = OP_HALFOPEN; // this should be enough to verify server present
$retries = 0; // don't retry connect on failure
$mbox = @imap_open($mailbox, $username, $password, $options, $retries);
if (!$mbox) {
die("skip could not connect to mailbox $mailbox");
}
imap_close($mbox);
?>

View File

@ -0,0 +1,261 @@
<?php
class MailConnecter
{
private $fp = null;
private static $instance;
private static $init = false;
private const HOST = 'localhost';
private const PORT = 143;
private const TIMEOUT = 10;
private function __construct()
{
if (($this->fp = @fsockopen(self::HOST, self::PORT)) === false) {
die('cannot open imap socket');
}
}
public static function getConnection(): self
{
if (!static::$init) {
static::$instance = new self();
}
return static::$instance;
}
public function disconnect(): void
{
fclose($this->fp);
}
public function fail(string $message): void
{
$this->disconnect();
die($message);
}
public function send(string $tag, string $command): void
{
fputs($this->fp, "{$tag} {$command}\r\n");
}
public function isSuccess(string $tag): bool
{
$start = time();
while (!feof($this->fp)) {
$line = fgets($this->fp);
if (!$line) {
return false;
}
if (str_contains($line, $tag)) {
if (preg_match('/(NO|BAD|failed|Failure)/i', $line)) {
return false;
}
return true;
}
if (time() - $start > self::TIMEOUT) {
$this->fail("{$tag} timeout");
}
}
return false;
}
public function getResponse(string $tag, bool $returnArray = false): string|array
{
$start = time();
$output = $returnArray ? [] : '';
while (!feof($this->fp)) {
$line = fgets($this->fp);
if (!$line) {
$this->fail("{$tag} failed");
}
if ($returnArray) {
$output[] = $line;
} else {
$output .= $line;
}
if (str_contains($line, $tag)) {
if (preg_match('/(NO|BAD|failed|Failure)/i', $line)) {
$this->fail("{$tag} failed");
}
return $output;
}
if (time() - $start > self::TIMEOUT) {
$this->fail("{$tag} timeout");
}
}
$this->fail("{$tag} failed");
}
}
class MailBox
{
private MailConnecter $mailConnecter;
private const PASSWORD = 'p4ssw0rd';
public const USERS = [
'webmaster@example.com',
'info@example.com',
'admin@example.com',
'foo@example.com',
];
private const LOGIN = 'A00001';
private const LOGOUT = 'A00002';
private const SELECT_MAILBOX = 'A00003';
private const SEARCH = 'A00004';
private const FETCH_HEADERS = 'A00005';
private const FETCH_BODY = 'A00006';
private const DELETE = 'A00007';
private const EXPUNGE = 'A00008';
private function __construct()
{
$this->mailConnecter = MailConnecter::getConnection();
}
public static function login(string $user): self
{
$self = new self();
$self->mailConnecter->send(self::LOGIN, 'LOGIN '.$user.' '.self::PASSWORD);
if (!$self->mailConnecter->isSuccess(self::LOGIN)) {
$self->mailConnecter->fail('login failed');
}
return $self;
}
public function logout(): void
{
$this->mailConnecter->send(self::LOGOUT, 'LOGOUT');
if (!$this->mailConnecter->isSuccess(self::LOGOUT)) {
$this->mailConnecter->fail('logout failed');
}
}
private function getUidsBySubject(string $subject): array
{
$this->mailConnecter->send(self::SELECT_MAILBOX, 'SELECT "INBOX"');
if (!$this->mailConnecter->isSuccess(self::SELECT_MAILBOX)) {
$this->mailConnecter->fail('select mailbox failed');
}
$this->mailConnecter->send(self::SEARCH, "UID SEARCH SUBJECT \"{$subject}\"");
$res = $this->mailConnecter->getResponse(self::SEARCH);
preg_match('/SEARCH ([0-9 ]+)/is', $res, $matches);
return isset($matches[1]) ? explode(' ', trim($matches[1])) : [];
}
public function getMailsBySubject(string $subject): MailCollection
{
return new MailCollection(array_map(
fn($uid) => $this->getHeaders($uid) + ['Body' => $this->getBody($uid)],
$this->getUidsBySubject($subject),
));
}
private function getHeaders(int $uid): array
{
$this->mailConnecter->send(self::FETCH_HEADERS, "UID FETCH {$uid} (BODY[HEADER])");
$res = $this->mailConnecter->getResponse(self::FETCH_HEADERS, true);
$headers = [];
foreach ($res as $line) {
$line = trim($line);
if (!$line) {
continue;
}
$items = explode(':', $line);
preg_match('/^(.+?):(.+?)$/', $line, $matches);
$key = trim($matches[1] ?? '');
$val = trim($matches[2] ?? '');
if (!$key || !$val || $val === self::FETCH_HEADERS.' OK UID completed' || $val === ')') {
continue;
}
$headers[$key] = $val;
}
return $headers;
}
private function getBody(int $uid): string
{
$this->mailConnecter->send(self::FETCH_BODY, "UID FETCH {$uid} (BODY[TEXT])");
$body = $this->mailConnecter->getResponse(self::FETCH_BODY, true);
$count = count($body);
if ($count <= 3) {
return '';
}
return implode('', array_slice($body, 1, $count - 3));
}
public function deleteMailsBySubject(string $subject): void
{
array_map(
fn($uid) => $this->mailConnecter->send(self::DELETE, "UID STORE {$uid} +FLAGS (\\Deleted)"),
$this->getUidsBySubject($subject),
);
$this->mailConnecter->send(self::EXPUNGE, 'EXPUNGE');
}
}
class MailCollection
{
public function __construct(private ?array $mailData) {}
public function isAsExpected(string $from, string $to, string $subject, string $message): bool
{
$result = true;
if (!$this->mailData) {
$result = false;
echo "Email data does not exist.\n";
}
if (!$this->count() > 1) {
$result = false;
echo "Multiple email data exist.\n";
}
if ($this->getHeader('From', true) !== $from) {
$result = false;
echo "from does not match.\n";
}
if ($this->getHeader('To', true) !== $to) {
$result = false;
echo "to does not match.\n";
}
if ($this->getHeader('Subject', true) !== $subject) {
$result = false;
echo "subject does not match.\n";
}
if (trim($this->getBody()) !== trim($message)) {
$result = false;
echo "body does not match.\n";
}
return $result;
}
public function count(): int
{
return count($this->mailData);
}
public function getHeader(string $field, bool $ignoreCases = false, int $offset = 0)
{
if ($ignoreCases) {
$mail = array_change_key_case($this->mailData[$offset] ?? []);
$field = strtolower($field);
} else {
$mail = $this->mailData[$offset] ?? [];
}
return $mail[$field] ?? null;
}
public function getBody(int $offset = 0): ?string
{
return $this->mailData[$offset]['Body'] ?? null;
}
}

View File

@ -1,89 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
ini_set("SMTP", "localhost");
ini_set("smtp_port", 2525);
ini_set("sendmail_from", "user@example.com");
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = mail($to, $subject, $message);
if ($res !== true) {
exit("TEST COMPLETED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
===DONE===
--EXPECTF--
*** Testing mail() : basic functionality ***
Warning: mail(): Failed to connect to mailserver at "localhost" port 2525, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in %s on line %d
TEST COMPLETED : Unable to send test email

View File

@ -1,89 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
ini_set("SMTP", "localplace");
ini_set("smtp_port", 25);
ini_set("sendmail_from", "user@example.com");
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = mail($to, $subject, $message);
if ($res !== true) {
exit("TEST COMPLETED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
===DONE===
--EXPECTF--
*** Testing mail() : basic functionality ***
Warning: mail(): Failed to connect to mailserver at "localplace" port 25, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in %s on line %d
TEST COMPLETED : Unable to send test email

View File

@ -1,88 +0,0 @@
--TEST--
Test mail() function : basic functionality
--EXTENSIONS--
imap
--CONFLICTS--
imap
--SKIPIF--
<?php
if( substr(PHP_OS, 0, 3) != 'WIN' ) {
die('skip...Windows only test');
}
require_once(__DIR__.'/mail_skipif.inc');
?>
--INI--
max_execution_time = 120
--FILE--
<?php
ini_set("SMTP", "localhost");
ini_set("smtp_port", 25);
echo "*** Testing mail() : basic functionality ***\n";
require_once(__DIR__.'/mail_include.inc');
$subject_prefix = "!**PHPT**!";
$to = "$username";
$subject = "$subject_prefix: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = mail($to, $subject, $message);
if ($res !== true) {
exit("TEST COMPLETED : Unable to send test email\n");
} else {
echo "Msg sent OK\n";
}
// Search for email message on the mail server using imap.
$imap_stream = imap_open($default_mailbox, $username, $password);
if ($imap_stream === false) {
echo "Cannot connect to IMAP server $server: " . imap_last_error() . "\n";
return false;
}
$found = false;
$repeat_count = 20; // we will repeat a max of 20 times
while (!$found && $repeat_count > 0) {
// sleep for a while to allow msg to be delivered
sleep(1);
$current_msg_count = imap_check($imap_stream)->Nmsgs;
// Iterate over recent msgs to find the one we sent above
for ($i = 1; $i <= $current_msg_count; $i++) {
// get hdr details
$hdr = imap_headerinfo($imap_stream, $i);
if (substr($hdr->Subject, 0 , strlen($subject_prefix)) == $subject_prefix) {
echo "Id of msg just sent is $i\n";
echo ".. delete it\n";
imap_delete($imap_stream, $i);
$found = true;
break;
}
}
$repeat_count -= 1;
}
if (!$found) {
echo "TEST FAILED: email not delivered\n";
} else {
echo "TEST PASSED: Msgs sent and deleted OK\n";
}
imap_close($imap_stream, CL_EXPUNGE);
?>
===DONE===
--EXPECTF--
*** Testing mail() : basic functionality ***
Warning: mail(): Bad Message Return Path in %s on line %d
TEST COMPLETED : Unable to send test email

View File

@ -0,0 +1,90 @@
--TEST--
Test mail() function : basic functionality (win)
--SKIPIF--
<?php die('skip test'); require_once __DIR__.'/mail_windows_skipif.inc'; ?>
--INI--
SMTP=localhost
smtp_port=25
--FILE--
<?php
require_once __DIR__.'/mail_util.inc';
$users = MailBox::USERS;
$from = ini_get('sendmail_from');
$cases = [
[
'label' => 'From is not set',
'premise' => function () {
ini_set('SMTP', 'localhost');
ini_set('smtp_port', 25);
}
],
[
'label' => 'Invalid port',
'premise' => function () {
ini_set('SMTP', 'localhost');
ini_set('smtp_port', 2525);
ini_set('sendmail_from', 'from@example.com');
}
],
[
'label' => 'Invalid host',
'premise' => function () {
ini_set('SMTP', 'localplace');
ini_set('smtp_port', 25);
ini_set('sendmail_from', 'from@example.com');
}
],
];
foreach ($cases as $index => ['label' => $label, 'premise' => $premise]) {
echo "========== {$label} ==========\n";
$premise();
$to = $users[$index];
$subject = "{$index}: Basic PHPT test for mail() function";
$message = <<<HERE
Description
bool mail ( string \$to , string \$subject , string \$message [, string \$additional_headers [, string \$additional_parameters]] )
Send an email message
HERE;
$res = mail($to, $subject, $message);
if ($res === true) {
echo "Email sent.\n";
}
$mailBox = MailBox::login($to);
$mail = $mailBox->getMailsBySubject($subject);
$mailBox->logout();
if ($mail->count() > 0) {
echo "Found the email.\n\n";
}
}
?>
--CLEAN--
<?php
require_once __DIR__.'/mail_util.inc';
for ($i = 0; $i <= 2; $i++) {
$subject = "{$i}: Basic PHPT test for mail() function";
$mailBox = MailBox::login(MailBox::USERS[$i]);
$mailBox->deleteMailsBySubject($subject);
$mailBox->logout();
}
?>
--EXPECTF--
========== From is not set ==========
Warning: mail(): Bad Message Return Path in %s on line %d
========== Invalid port ==========
Warning: mail(): Failed to connect to mailserver at "localhost" port 2525, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in %s on line %d
========== Invalid host ==========
Warning: mail(): Failed to connect to mailserver at "localplace" port 1025, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in %s on line %d

View File

@ -0,0 +1,15 @@
<?php
if(substr(PHP_OS, 0, 3) !== 'WIN') {
die('skip windows only test');
}
$connection = @fsockopen('localhost', 25);
if ($connection === false) {
die('skip unable to open smtp socket');
}
$connection = @fsockopen('localhost', 143);
if ($connection === false) {
die('skip unable to open imap socket');
}
?>