Adding #3235 and reorganizing tests
This commit is contained in:
parent
bda1fee442
commit
95ff455f9d
|
|
@ -1298,6 +1298,7 @@ class PHPMailer
|
|||
// Emit a runtime notice to recommend using the IMAP extension for full RFC822 parsing
|
||||
trigger_error(self::lang('imap_recommended'), E_USER_NOTICE);
|
||||
|
||||
$addresses = [];
|
||||
$list = explode(',', $addrstr);
|
||||
foreach ($list as $address) {
|
||||
$address = trim($address);
|
||||
|
|
@ -1311,21 +1312,10 @@ class PHPMailer
|
|||
];
|
||||
}
|
||||
} else {
|
||||
list($name, $email) = explode('<', $address);
|
||||
$email = trim(str_replace('>', '', $email));
|
||||
$name = trim($name);
|
||||
$parsed = self::parseEmailString($address);
|
||||
$email = $parsed['email'];
|
||||
if (static::validateAddress($email)) {
|
||||
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
|
||||
//If this name is encoded, decode it
|
||||
if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
|
||||
$origCharset = mb_internal_encoding();
|
||||
mb_internal_encoding($charset);
|
||||
//Undo any RFC2047-encoded spaces-as-underscores
|
||||
$name = str_replace('_', '=20', $name);
|
||||
//Decode the name
|
||||
$name = mb_decode_mimeheader($name);
|
||||
mb_internal_encoding($origCharset);
|
||||
}
|
||||
$name = static::decodeHeader($parsed['name'], $charset);
|
||||
$addresses[] = [
|
||||
//Remove any surrounding quotes and spaces from the name
|
||||
'name' => trim($name, '\'" '),
|
||||
|
|
@ -1338,6 +1328,42 @@ class PHPMailer
|
|||
return $addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string containing an email address with an optional name
|
||||
* and divide it into a name and email address.
|
||||
*
|
||||
* @param string $input The email with name.
|
||||
*
|
||||
* @return array{name: string, email: string}
|
||||
*/
|
||||
private static function parseEmailString($input)
|
||||
{
|
||||
$input = trim((string)$input);
|
||||
|
||||
if ($input === '') {
|
||||
return ['name' => '', 'email' => ''];
|
||||
}
|
||||
|
||||
$pattern = '/^\s*(?:(?:"([^"]*)"|\'([^\']*)\'|([^<]*?))\s*)?<\s*([^>]+)\s*>\s*$/';
|
||||
if (preg_match($pattern, $input, $matches)) {
|
||||
$name = '';
|
||||
// Double quotes including special scenarios.
|
||||
if (isset($matches[1]) && $matches[1] !== '') {
|
||||
$name = $matches[1];
|
||||
// Single quotes including special scenarios.
|
||||
} elseif (isset($matches[2]) && $matches[2] !== '') {
|
||||
$name = $matches[2];
|
||||
// Simplest scenario, name and email are in the format "Name <email>".
|
||||
} elseif (isset($matches[3])) {
|
||||
$name = trim($matches[3]);
|
||||
}
|
||||
|
||||
return ['name' => $name, 'email' => trim($matches[4])];
|
||||
}
|
||||
|
||||
return ['name' => '', 'email' => $input];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the From and FromName properties.
|
||||
*
|
||||
|
|
@ -3727,14 +3753,8 @@ class PHPMailer
|
|||
// Decode the header value
|
||||
$value = mb_decode_mimeheader($value);
|
||||
mb_internal_encoding($origCharset);
|
||||
} elseif ($hasEncodedWord && function_exists('iconv_mime_decode')) {
|
||||
// Use iconv as a fallback when mbstring is not available
|
||||
$mode = defined('ICONV_MIME_DECODE_CONTINUE_ON_ERROR') ? ICONV_MIME_DECODE_CONTINUE_ON_ERROR : 0;
|
||||
$decoded = @iconv_mime_decode($value, $mode, $charset);
|
||||
if ($decoded !== false) {
|
||||
$value = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,8 @@ EOT;
|
|||
|
||||
/**
|
||||
* Send a message containing ISO-8859-1 text.
|
||||
*
|
||||
* @requires extension mbstring
|
||||
*/
|
||||
public function testHtmlIso8859()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,52 +19,32 @@ use Yoast\PHPUnitPolyfills\TestCases\TestCase;
|
|||
|
||||
/**
|
||||
* Test RFC822 address splitting.
|
||||
*
|
||||
* @todo Additional tests need to be added to verify the correct handling of inputs which
|
||||
* include a different encoding than UTF8 or even mixed encoding. For more information
|
||||
* on what these test cases should look like and should test, please see
|
||||
* {@link https://github.com/PHPMailer/PHPMailer/pull/2449} for context.
|
||||
*
|
||||
* @covers \PHPMailer\PHPMailer\PHPMailer::parseAddresses
|
||||
*/
|
||||
final class ParseAddressesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test RFC822 address splitting using the PHPMailer native implementation
|
||||
* Verify the expectations.
|
||||
*
|
||||
* @dataProvider dataAddressSplitting
|
||||
* Abstracted out as the same verification needs to be done for every test, just with different data.
|
||||
*
|
||||
* @param string $addrstr The address list string.
|
||||
* @param array $expected The expected function output.
|
||||
* @param string $charset Optional. The charset to use.
|
||||
*/
|
||||
public function testAddressSplitting($addrstr, $expected)
|
||||
{
|
||||
$parsed = PHPMailer::parseAddresses($addrstr, null, PHPMailer::CHARSET_UTF8);
|
||||
|
||||
$this->verifyExpectations($parsed, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test decodeHeader using the PHPMailer
|
||||
* with the Mbstring extension available.
|
||||
*
|
||||
* @dataProvider dataDecodeHeader
|
||||
*
|
||||
* @param string $addrstr The header string.
|
||||
* @param string $actual The actual function output.
|
||||
* @param array $expected The expected function output.
|
||||
*/
|
||||
public function testDecodeHeader($str, $expected)
|
||||
protected function verifyExpectations($actual, $expected)
|
||||
{
|
||||
$parsed = PHPMailer::decodeHeader($str, PHPMailer::CHARSET_UTF8);
|
||||
|
||||
$this->assertEquals($parsed, $expected);
|
||||
self::assertIsArray($actual, 'parseAddresses() did not return an array');
|
||||
self::assertSame(
|
||||
$expected,
|
||||
$actual,
|
||||
'The return value from parseAddresses() did not match the expected output'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test RFC822 address splitting using the native implementation
|
||||
*
|
||||
* @dataProvider dataAddressSplittingNative
|
||||
* @covers \PHPMailer\PHPMailer\PHPMailer::parseSimplerAddresses
|
||||
*
|
||||
* @param string $addrstr The address list string.
|
||||
* @param array $expected The expected function output.
|
||||
|
|
@ -72,6 +52,7 @@ final class ParseAddressesTest extends TestCase
|
|||
*/
|
||||
public function testAddressSplittingNative($addrstr, $expected, $charset = PHPMailer::CHARSET_ISO88591)
|
||||
{
|
||||
xdebug_break();
|
||||
error_reporting(E_ALL & ~E_USER_NOTICE);
|
||||
$reflMethod = new ReflectionMethod(PHPMailer::class, 'parseSimplerAddresses');
|
||||
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
|
||||
|
|
@ -107,22 +88,71 @@ final class ParseAddressesTest extends TestCase
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the expectations.
|
||||
/**
|
||||
* Test if email addresses are parsed and split into a name and address.
|
||||
*
|
||||
* Abstracted out as the same verification needs to be done for every test, just with different data.
|
||||
*
|
||||
* @param string $actual The actual function output.
|
||||
* @param array $expected The expected function output.
|
||||
* @dataProvider dataParseEmailString
|
||||
* @covers \PHPMailer\PHPMailer\PHPMailer::parseEmailString
|
||||
* @param mixed $addrstr
|
||||
* @param mixed $expected
|
||||
*/
|
||||
protected function verifyExpectations($actual, $expected)
|
||||
public function testParseEmailString($addrstr, $expected)
|
||||
{
|
||||
self::assertIsArray($actual, 'parseAddresses() did not return an array');
|
||||
self::assertSame(
|
||||
$expected,
|
||||
$actual,
|
||||
'The return value from parseAddresses() did not match the expected output'
|
||||
);
|
||||
$reflMethod = new ReflectionMethod(PHPMailer::class, 'parseEmailString');
|
||||
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
|
||||
$parsed = $reflMethod->invoke(null, $addrstr);
|
||||
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
|
||||
$this->assertEquals($parsed, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testParseEmailString.
|
||||
*
|
||||
* @return array The array is expected to have an `addrstr` and an `expected` key.
|
||||
*/
|
||||
public function dataParseEmailString()
|
||||
{
|
||||
return [
|
||||
'Valid address: simple address' => [
|
||||
'addrstr' => 'Joe User <joe@example.com>',
|
||||
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
|
||||
],
|
||||
'Valid address: simple address with double quotes' => [
|
||||
'addrstr' => '"Joe User" <joe@example.com>',
|
||||
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
|
||||
],
|
||||
'Valid address: simple address with single quotes' => [
|
||||
'addrstr' => '\'Joe User\' <joe@example.com>',
|
||||
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
|
||||
],
|
||||
'Valid address: complex address with single quotes' => [
|
||||
'addrstr' => '\'Joe<User\' <joe@example.com>',
|
||||
'expected' => ['name' => 'Joe<User', 'email' => 'joe@example.com'],
|
||||
],
|
||||
'Valid address: complex address with triangle bracket' => [
|
||||
'addrstr' => '"test<stage" <test@example.com>',
|
||||
'expected' => ['name' => 'test<stage', 'email' => 'test@example.com'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test RFC822 address splitting using the PHPMailer native implementation
|
||||
*
|
||||
* @dataProvider dataAddressSplitting
|
||||
* @covers \PHPMailer\PHPMailer\PHPMailer::parseAddresses
|
||||
*
|
||||
* @requires extension mbstring
|
||||
*
|
||||
* @param string $addrstr The address list string.
|
||||
* @param array $expected The expected function output.
|
||||
* @param string $charset Optional. The charset to use.
|
||||
*/
|
||||
public function testAddressSplitting($addrstr, $expected)
|
||||
{
|
||||
$parsed = PHPMailer::parseAddresses($addrstr, null, PHPMailer::CHARSET_UTF8);
|
||||
|
||||
$this->verifyExpectations($parsed, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -218,6 +248,25 @@ final class ParseAddressesTest extends TestCase
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test decodeHeader using the PHPMailer
|
||||
* with the Mbstring extension available.
|
||||
*
|
||||
* @dataProvider dataDecodeHeader
|
||||
* @covers \PHPMailer\PHPMailer\PHPMailer::decodeHeader
|
||||
*
|
||||
* @requires extension mbstring
|
||||
*
|
||||
* @param string $addrstr The header string.
|
||||
* @param array $expected The expected function output.
|
||||
*/
|
||||
public function testDecodeHeader($str, $expected)
|
||||
{
|
||||
$parsed = PHPMailer::decodeHeader($str, PHPMailer::CHARSET_UTF8);
|
||||
|
||||
$this->assertEquals($parsed, $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for decodeHeader.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue