Skip to content

Commit 0976a33

Browse files
authored
Merge pull request #174 from danielabyan/feature/fold-header-properly
Fold a string with the correct length
2 parents b217a7a + 71ec62d commit 0976a33

File tree

5 files changed

+45
-24
lines changed

5 files changed

+45
-24
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"php": "~8.0.0 || ~8.1.0",
1212
"ext-iconv": "*",
1313
"laminas/laminas-loader": "^2.8.0",
14-
"laminas/laminas-mime": "^2.9.1",
14+
"laminas/laminas-mime": "^2.10.0",
1515
"laminas/laminas-stdlib": "^3.11.0",
1616
"laminas/laminas-validator": "^2.23.0",
1717
"symfony/polyfill-mbstring": "^1.16.0",

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Header/HeaderWrap.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
use function iconv_mime_encode;
1313
use function implode;
1414
use function str_contains;
15+
use function str_pad;
1516
use function str_starts_with;
1617
use function strlen;
1718
use function strpos;
19+
use function substr;
1820
use function wordwrap;
1921

2022
use const ICONV_MIME_DECODE_CONTINUE_ON_ERROR;
@@ -52,11 +54,23 @@ public static function wrap($value, HeaderInterface $header)
5254
*/
5355
protected static function wrapUnstructuredHeader($value, HeaderInterface $header)
5456
{
55-
$encoding = $header->getEncoding();
57+
$headerNameColonSize = strlen($header->getFieldName() . ': ');
58+
$encoding = $header->getEncoding();
59+
5660
if ($encoding == 'ASCII') {
57-
return wordwrap($value, 78, Headers::FOLDING);
61+
/*
62+
* Before folding the header line, it is necessary to calculate the length of the
63+
* entire header (including the name and colon). We need to put a stub at the
64+
* beginning of the value so that the folding is performed correctly.
65+
*/
66+
$headerLine = str_pad('0', $headerNameColonSize, '0') . $value;
67+
$foldedHeaderLine = wordwrap($headerLine, 78, Headers::FOLDING);
68+
69+
// Remove the stub and return the header folded value.
70+
return substr($foldedHeaderLine, $headerNameColonSize);
5871
}
59-
return static::mimeEncodeValue($value, $encoding, 78);
72+
73+
return static::mimeEncodeValue($value, $encoding, 78, $headerNameColonSize);
6074
}
6175

6276
/**
@@ -88,14 +102,19 @@ protected static function wrapStructuredHeader($value, StructuredInterface $head
88102
* Performs quoted-printable encoding on a value, setting maximum
89103
* line-length to 998.
90104
*
91-
* @param string $value
92-
* @param string $encoding
93-
* @param int $lineLength maximum line-length, by default 998
105+
* @param string $value
106+
* @param string $encoding
107+
* @param int $lineLength Maximum line-length, by default 998
108+
* @param positive-int|0 $firstLineGapSize When folding a line, it is necessary to calculate
109+
* the length of the entire line (together with the
110+
* header name). Therefore, you can specify the header
111+
* name and colon length in this argument to fold the
112+
* string properly.
94113
* @return string Returns the mime encode value without the last line ending
95114
*/
96-
public static function mimeEncodeValue($value, $encoding, $lineLength = 998)
115+
public static function mimeEncodeValue($value, $encoding, $lineLength = 998, $firstLineGapSize = 0)
97116
{
98-
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL);
117+
return Mime::encodeQuotedPrintableHeader($value, $encoding, $lineLength, Headers::EOL, $firstLineGapSize);
99118
}
100119

101120
/**

test/Header/SubjectTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use PHPUnit\Framework\TestCase;
88

99
use function str_repeat;
10-
use function wordwrap;
1110

1211
/**
1312
* @group Laminas_Mail
@@ -21,7 +20,10 @@ public function testHeaderFolding(): void
2120
$subject = new Header\Subject();
2221
$subject->setSubject($string);
2322

24-
$expected = wordwrap($string, 78, "\r\n ");
23+
$expected = "foobarblahblahblah baz batfoobarblahblahblah baz\r\n "
24+
. "batfoobarblahblahblah baz batfoobarblahblahblah baz batfoobarblahblahblah baz\r\n "
25+
. "batfoobarblahblahblah baz batfoobarblahblahblah baz batfoobarblahblahblah baz\r\n "
26+
. "batfoobarblahblahblah baz batfoobarblahblahblah baz bat";
2527
$test = $subject->getFieldValue(Header\HeaderInterface::FORMAT_ENCODED);
2628
$this->assertEquals($expected, $test);
2729
}

test/MessageTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -884,8 +884,8 @@ public function testMessageSubjectFromString(): void
884884
$mail = Message::fromString($rawMessage);
885885

886886
$this->assertStringContainsString(
887-
'Subject: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
888-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
887+
'Subject: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
888+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
889889
$mail->toString()
890890
);
891891
}
@@ -896,8 +896,8 @@ public function testMessageSubjectSetSubject(): void
896896
$mail->setSubject('Non “ascii” characters like accented vowels òàùèéì');
897897

898898
$this->assertStringContainsString(
899-
'Subject: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
900-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
899+
'Subject: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
900+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
901901
$mail->toString()
902902
);
903903
}
@@ -909,8 +909,8 @@ public function testCorrectHeaderEncodingAddHeader(): void
909909
$mail->getHeaders()->addHeader($header);
910910

911911
$this->assertStringContainsString(
912-
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
913-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
912+
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
913+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
914914
$mail->toString()
915915
);
916916
}
@@ -924,8 +924,8 @@ public function testCorrectHeaderEncodingSetHeaders(): void
924924
$mail->setHeaders($headers);
925925

926926
$this->assertStringContainsString(
927-
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
928-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
927+
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
928+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
929929
$mail->toString()
930930
);
931931
}
@@ -939,8 +939,8 @@ public function testCorrectHeaderEncodingFromString(): void
939939
$mail->getHeaders()->addHeader($header);
940940

941941
$this->assertStringContainsString(
942-
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
943-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
942+
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
943+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=',
944944
$mail->toString()
945945
);
946946
}
@@ -957,8 +957,8 @@ public function testCorrectHeaderEncodingFromStringAndSetHeaders(): void
957957
$mail->setHeaders($headers);
958958

959959
$this->assertStringContainsString(
960-
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20accented=20?=' . "\r\n"
961-
. ' =?UTF-8?Q?vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=' . "\r\n",
960+
'X-Test: =?UTF-8?Q?Non=20=E2=80=9Cascii=E2=80=9D=20characters=20like=20?=' . "\r\n"
961+
. ' =?UTF-8?Q?accented=20vowels=20=C3=B2=C3=A0=C3=B9=C3=A8=C3=A9=C3=AC?=',
962962
$mail->toString()
963963
);
964964
}

0 commit comments

Comments
 (0)