EncodeQ() cant handle some characters
A full-featured email creation and transfer class for PHP
Brought to you by:
coolbru
This is old as EncodeQ() probably. Just spoted it in a 2003 version.
The problem is that that ord() can only handle 1character at a time.
And when used in preg_replace ith the /e moifier. Some character are backslashed.
When this happens, ord() only see the slash and not the real character.
So stripping slashes is necessary before calling ord. So:
public function EncodeQ ($str, $position = 'text') {
// There should not be any EOL in the string
$encoded = preg_replace('/[\r\n]*/', '', $str);
switch (strtolower($position)) { case 'phrase': $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); break; case 'comment': $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded); case 'text': default: // Replace every high ascii, control =, ? and _ characters //TODO using /e (equivalent to eval()) is probably not a good idea $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', "'='.sprintf('%02X', ord('\\1'))", $encoded); break; }
becomes:
public function EncodeQ ($str, $position = 'text') {
// There should not be any EOL in the string
$encoded = preg_replace('/[\r\n]*/', '', $str);
switch (strtolower($position)) { case 'phrase': $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord(stripslashes('\\1')))", $encoded); break; case 'comment': $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord(stripslashes('\\1')))", $encoded); case 'text': default: // Replace every high ascii, control =, ? and _ characters //TODO using /e (equivalent to eval()) is probably not a good idea $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', "'='.sprintf('%02X', ord(stripslashes('\\1')))", $encoded); break; }
I was hit by this bug, too, and the proposed change is both correct and works.
What Raul is referring to is this text passage in the manual for preg_replace() http://php.net/manual/en/function.preg-replace.php:
"When using the e modifier, this function escapes some characters (namely ', ", \ and NULL) in the strings that replace the backreferences."
A simple test case would be sending an e-mail using display name, for example:
$mail->AddAddress('foo@example.com', 'Tim "The Book" O\'Reilly');
At the recipient, however, the address appears as:
Tim \The Book\ O'Reilly foo@example.com
since the quotes are automatically escaped by preg_replace() and only the backslash comes through ord().
Fixed in later versions, added to unit tests on GitHub