#30 [Com]: Bug in MAIL_mime::_encodeHeaders()
| From: | samm at os2 dot ru | Date: | Thu, 09 Oct 2003 00:40:59 +0000 |
| Subject: | #30 [Com]: Bug in MAIL_mime::_encodeHeaders() | ||
| References: | 1 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-22505@lists.php.net to get a copy of this message | ||
ID: 30
Comment by: samm at os2 dot ru
Reported By: ed at avi dot ru
Status: Open
Bug Type: Mail_Mime
Operating System: All
PHP Version: Irrelevant
New Comment:
10x for solution. I used your patch and it work correctly for my
subjects.
Previous Comments:
------------------------------------------------------------------------
[2003-09-23 05:13:08] ed at avi dot ru
Description:
------------
Hello!
I tried to use PEAR module Mail_mime to compose a message with cyrillic
subject and noticed that whitespaces between cyrillic words in
resulting message are missing (Cyrillic letters are in 0x80-0xFF area).
The investigation discovered that the Mail_mime::encodeHeaders() method
is working incorrectly. Let's imagine that we have the following
subject (or any other header, it doesn't matter):
AAA BBB BBB AAA BBB
where A is a latin character and B is a cyrillic character. Your
regular expression will detect 3 BBB patterns and will encode them
separately:
AAA =?charset?Q?=xx=xx=xx?= =?charset?Q?=xx=xx=xx?= AAA
=?charset?Q?=xx=xx=xx?=
And what we see? First two BBB patterns produced two sequential
RFC-2047 'encoded-word' patterns, which is a) incorrect, because two
sequential 'encoded-word' patterns must be separated by CRLF SPACE, not
by SPACE only; b) is understood by mailers as CRLF SPACE and thus
translataed as empty string. Oops...
The solution is to change the regular expression so that it could find
not the single 'words-with-[0x80-0xFF]' patterns, but space-separated
sequences of such words. And it will be better to include '-' symbol in
\w qualifier thus treating words with '-' as solid words. The regex
is:
/([\w\-]*[\x80-\xFF]+[\w\-]*(\s+[\w\-]*[\x80-\xFF]+[\w\-]*)*)\s*/
And the replacing regex also needs improvement: as per RFC-2047
'encoded-word' pattern must not contain spaces and tabs to be treated
as single atom; it also must not contain underscores, equal and
question signs (they are special characters and must be escaped); the
correct regex is:
/([\s_=\?\x80-\xFF])/e
And one more improvement: it sometimes better (as per RFC-2047) to
encode headers not as quoted-printable but as base64 (if header
consists mainly of 0x80-0xFF characters). The extended and corrected
function is here:
/**
* Encodes a header as per RFC2047
*
* @param string $input The header data to encode
* @return string Encoded data
* @access private
*/
function _encodeHeaders($input)
{
foreach ($input as $hdr_name => $hdr_value) {
preg_match_all('/([\w\-]*[\x80-\xFF]+[\w\-]*(\s+[\w\-]*[\x80-\xFF]+[\w\-]*)*)\s*/',
$hdr_value, $matches);
foreach ($matches[1] as $value) {
switch ($head_encoding = $this->_build_params['head_encoding']) {
case 'base64':
$symbol = 'B';
$replacement = base64_encode($value);
break;
default:
if ($head_encoding != 'quoted-printable') {
PEAR::raiseError(
'Invalid header encoding specified; using
quoted-printable
instead',
NULL,
PEAR_ERROR_TRIGGER,
E_USER_WARNING
);
}
$symbol = 'Q';
$replacement = preg_replace('/([\s_=\?\x80-\xFF])/e', '"=" .
strtoupper(dechex(ord("\1")))', $value);
}
$hdr_value = str_replace($value, '=?' .
$this->_build_params['head_charset'] . '?' . $symbol . '?' .
$replacement . '?=', $hdr_value);
}
$input[$hdr_name] = $hdr_value;
}
return $input;
}
The function steel may need some inprovement, because headers must be
divided on CRLF SPACE -separated parts no longer than 76 characters,
but it's another story :) Anyway, thanks for attention. Let me know if
you find these improvements useful and include them in next version of
Mail_mime. Bye!
With best regards, Edward Surov
------------------------------------------------------------------------
--
Edit this bug report at http://pear.php.net/bugs/bug.php?id=30&edit=1