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

Content Type Header Parsing #211

Merged
merged 5 commits into from
Jun 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it now correctly ignores them.

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