Skip to content
This repository was archived by the owner on Jan 30, 2020. It is now read-only.

Commit d27d631

Browse files
committed
Merge branch 'hotfix/211-content-type-parsing'
Close #211 Fixes #179
2 parents 79f0f72 + c2b4f76 commit d27d631

File tree

6 files changed

+45
-13
lines changed

6 files changed

+45
-13
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ All notable changes to this project will be documented in this file, in reverse
4242

4343
### Fixed
4444

45+
- [#211](https://github.com/zendframework/zend-mail/pull/211) fixes how the `ContentType` header class parses the value it receives. Previously,
46+
it was incorrectly splitting the value on semi-colons that were inside quotes; in now correctly
47+
ignores them.
48+
4549
- [#204](https://github.com/zendframework/zend-mail/pull/204) fixes `HeaderWrap::mimeDecodeValue()` behavior when handling a multiline UTF-8
4650
header split across a character. The fix will only work when ext-imap is present, however.
4751

phpunit.xml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
<php>
2525
<ini name="date.timezone" value="UTC"/>
26+
<ini name="error_reporting" value="-1"/>
2627

2728
<!-- OB_ENABLED should be enabled for some tests to check if all
2829
functionality works as expected. Such tests include those for

src/Header/AbstractAddressList.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static function fromString($headerLine)
5858
// split value on ","
5959
$fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
6060
$fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
61-
$values = AddressListParser::parse($fieldValue);
61+
$values = ListParser::parse($fieldValue);
6262

6363
$wasEncoded = false;
6464
$addresses = array_map(

src/Header/ContentType.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,20 @@ public static function fromString($headerLine)
4040
}
4141

4242
$value = str_replace(Headers::FOLDING, ' ', $value);
43-
$values = preg_split('#\s*;\s*#', $value);
43+
$parts = explode(';', $value, 2);
4444

45-
$type = array_shift($values);
4645
$header = new static();
47-
$header->setType($type);
46+
$header->setType($parts[0]);
4847

49-
// Remove empty values
50-
$values = array_filter($values);
48+
if (isset($parts[1])) {
49+
$values = ListParser::parse(trim($parts[1]), [';', '=']);
50+
$length = count($values);
5151

52-
foreach ($values as $keyValuePair) {
53-
list($key, $value) = explode('=', $keyValuePair, 2);
54-
$value = trim($value, "'\" \t\n\r\0\x0B");
55-
$header->addParameter($key, $value);
52+
for ($i = 0; $i < $length; $i += 2) {
53+
$value = $values[$i + 1];
54+
$value = trim($value, "'\" \t\n\r\0\x0B");
55+
$header->addParameter($values[$i], $value);
56+
}
5657
}
5758

5859
return $header;

src/Header/AddressListParser.php renamed to src/Header/ListParser.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99

1010
use function in_array;
1111

12-
class AddressListParser
12+
class ListParser
1313
{
1414
const CHAR_QUOTES = ['\'', '"'];
1515
const CHAR_DELIMS = [',', ';'];
1616
const CHAR_ESCAPE = '\\';
1717

1818
/**
1919
* @param string $value
20+
* @param array $delims Delimiters allowed between values; parser will
21+
* split on these, as long as they are not within quotes. Defaults
22+
* to ListParser::CHAR_DELIMS.
2023
* @return array
2124
*/
22-
public static function parse($value)
25+
public static function parse($value, array $delims = self::CHAR_DELIMS)
2326
{
2427
$values = [];
2528
$length = strlen($value);
@@ -40,7 +43,7 @@ public static function parse($value)
4043

4144
// If we are not in a quoted string, and have a delimiter, append
4245
// the current value to the list, and reset the current value.
43-
if (in_array($char, self::CHAR_DELIMS, true) && ! $inQuote) {
46+
if (in_array($char, $delims, true) && ! $inQuote) {
4447
$values [] = $currentValue;
4548
$currentValue = '';
4649
continue;

test/Header/ContentTypeTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ public function testExtractsExtraInformationWithoutBeingConfusedByTrailingSemico
4545
$this->assertEquals($header->getParameters(), ['name' => 'foo.pdf']);
4646
}
4747

48+
public static function getLiteralData()
49+
{
50+
return [
51+
[
52+
['name' => 'foo; bar.txt'],
53+
'text/plain; name="foo; bar.txt"'
54+
],
55+
[
56+
['name' => 'foo&bar.txt'],
57+
'text/plain; name="foo&bar.txt"'
58+
],
59+
];
60+
}
61+
62+
/**
63+
* @dataProvider getLiteralData
64+
*/
65+
public function testHandlesLiterals(array $expected, $header)
66+
{
67+
$header = ContentType::fromString('Content-Type: '.$header);
68+
$this->assertEquals($expected, $header->getParameters());
69+
}
70+
4871
/**
4972
* @dataProvider setTypeProvider
5073
*/

0 commit comments

Comments
 (0)