#30 [Com]: Bug in MAIL_mime::_encodeHeaders()

From: 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

« previous php.pear.dev (#22505) next »