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

Commit

Permalink
Merge branch 'hotfix/211-content-type-parsing' into develop
Browse files Browse the repository at this point in the history
Forward port #211
  • Loading branch information
weierophinney committed Jun 7, 2018
2 parents b32ea11 + c2b4f76 commit 7104133
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ All notable changes to this project will be documented in this file, in reverse

### Fixed

- [#211](https://github.com/zendframework/zend-mail/pull/211) fixes how the `ContentType` header class parses the value it receives. Previously,
it was incorrectly splitting the value on semi-colons that were inside quotes; in now correctly
ignores them.

- [#204](https://github.com/zendframework/zend-mail/pull/204) fixes `HeaderWrap::mimeDecodeValue()` behavior when handling a multiline UTF-8
header split across a character. The fix will only work when ext-imap is present, however.

Expand Down
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

<php>
<ini name="date.timezone" value="UTC"/>
<ini name="error_reporting" value="-1"/>

<!-- OB_ENABLED should be enabled for some tests to check if all
functionality works as expected. Such tests include those for
Expand Down
2 changes: 1 addition & 1 deletion src/Header/AbstractAddressList.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static function fromString($headerLine)
// split value on ","
$fieldValue = str_replace(Headers::FOLDING, ' ', $fieldValue);
$fieldValue = preg_replace('/[^:]+:([^;]*);/', '$1,', $fieldValue);
$values = AddressListParser::parse($fieldValue);
$values = ListParser::parse($fieldValue);

$wasEncoded = false;
$addresses = array_map(
Expand Down
19 changes: 10 additions & 9 deletions src/Header/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,20 @@ public static function fromString($headerLine)
}

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

$type = array_shift($values);
$header = new static();
$header->setType($type);
$header->setType($parts[0]);

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

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

return $header;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@

use function in_array;

class AddressListParser
class ListParser
{
const CHAR_QUOTES = ['\'', '"'];
const CHAR_DELIMS = [',', ';'];
const CHAR_ESCAPE = '\\';

/**
* @param string $value
* @param array $delims Delimiters allowed between values; parser will
* split on these, as long as they are not within quotes. Defaults
* to ListParser::CHAR_DELIMS.
* @return array
*/
public static function parse($value)
public static function parse($value, array $delims = self::CHAR_DELIMS)
{
$values = [];
$length = strlen($value);
Expand All @@ -40,7 +43,7 @@ public static function parse($value)

// If we are not in a quoted string, and have a delimiter, append
// the current value to the list, and reset the current value.
if (in_array($char, self::CHAR_DELIMS, true) && ! $inQuote) {
if (in_array($char, $delims, true) && ! $inQuote) {
$values [] = $currentValue;
$currentValue = '';
continue;
Expand Down
23 changes: 23 additions & 0 deletions test/Header/ContentTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,29 @@ public function testExtractsExtraInformationWithoutBeingConfusedByTrailingSemico
$this->assertEquals($header->getParameters(), ['name' => 'foo.pdf']);
}

public static function getLiteralData()
{
return [
[
['name' => 'foo; bar.txt'],
'text/plain; name="foo; bar.txt"'
],
[
['name' => 'foo&bar.txt'],
'text/plain; name="foo&bar.txt"'
],
];
}

/**
* @dataProvider getLiteralData
*/
public function testHandlesLiterals(array $expected, $header)
{
$header = ContentType::fromString('Content-Type: '.$header);
$this->assertEquals($expected, $header->getParameters());
}

/**
* @dataProvider setTypeProvider
*/
Expand Down

0 comments on commit 7104133

Please sign in to comment.