Created
October 11, 2012 07:06
-
-
Save narfbg/3870694 to your computer and use it in GitHub Desktop.
RC Fix issues #1409 & #1498 (broken multibyte email headers)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/system/libraries/Email.php b/system/libraries/Email.php | |
index 698cb76..764d16d 100644 | |
--- a/system/libraries/Email.php | |
+++ b/system/libraries/Email.php | |
@@ -98,7 +98,7 @@ class CI_Email { | |
*/ | |
public function __construct($config = array()) | |
{ | |
- $this->charset = strtoupper(config_item('charset')); | |
+ $this->charset = config_item('charset'); | |
if (count($config) > 0) | |
{ | |
@@ -110,6 +110,8 @@ class CI_Email { | |
$this->_safe_mode = (bool) @ini_get('safe_mode'); | |
} | |
+ $this->charset = strtoupper($this->charset); | |
+ | |
log_message('debug', 'Email Class Initialized'); | |
} | |
@@ -1188,57 +1190,66 @@ class CI_Email { | |
*/ | |
protected function _prep_q_encoding($str, $from = FALSE) | |
{ | |
- $str = str_replace(array("\r", "\n"), array('', ''), $str); | |
- | |
- // Line length must not exceed 76 characters, so we adjust for | |
- // a space, 7 extra characters =??Q??=, and the charset that we will add to each line | |
- $limit = 75 - 7 - strlen($this->charset); | |
- | |
- // these special characters must be converted too | |
- $convert = array('_', '=', '?'); | |
+ $str = str_replace(array("\r", "\n"), '', $str); | |
- if ($from === TRUE) | |
+ if ($this->charset === 'UTF-8') | |
{ | |
- $convert[] = ','; | |
- $convert[] = ';'; | |
+ if (MB_ENABLED === TRUE) | |
+ { | |
+ return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf); | |
+ } | |
+ elseif (extension_loaded('iconv')) | |
+ { | |
+ $output = @iconv_mime_encode('', $str, | |
+ array( | |
+ 'scheme' => 'Q', | |
+ 'line-length' => 76, | |
+ 'input-charset' => $this->charset, | |
+ 'output-charset' => $this->charset, | |
+ 'line-break-chars' => $this->crlf | |
+ ) | |
+ ); | |
+ | |
+ // There are reports that iconv_mime_encode() might fail and return FALSE | |
+ if ($output !== FALSE) | |
+ { | |
+ // iconv_mime_encode() will always put a header field name. | |
+ // We've passed it an empty one, but it still prepends our | |
+ // encoded string with ': ', so we need to strip it. | |
+ return substr($output, 2); | |
+ } | |
+ | |
+ $chars = iconv_strlen($str, 'UTF-8'); | |
+ } | |
} | |
- $output = ''; | |
- $temp = ''; | |
+ // We might already have this set for UTF-8 | |
+ isset($chars) OR $chars = strlen($str); | |
- for ($i = 0, $length = strlen($str); $i < $length; $i++) | |
+ $output = '=?'.$this->charset.'?Q?'; | |
+ for ($i = 0, $length = strlen($output), $iconv = extension_loaded('iconv'); $i < $chars; $i++) | |
{ | |
- // Grab the next character | |
- $char = $str[$i]; | |
- $ascii = ord($char); | |
- | |
- // convert ALL non-printable ASCII characters and our specials | |
- if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert)) | |
- { | |
- $char = '='.dechex($ascii); | |
- } | |
+ $chr = ($this->charset === 'UTF-8' && $iconv === TRUE) | |
+ ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2)) | |
+ : '='.strtoupper(bin2hex($str[$i])); | |
- // handle regular spaces a bit more compactly than =20 | |
- if ($ascii === 32) | |
+ // RFC 2045 sets a limit of 76 characters per line. | |
+ // We'll append ?= to the end of each line though. | |
+ if ($length + ($l = strlen($chr)) > 74) | |
{ | |
- $char = '_'; | |
+ $output .= '?='.$this->crlf // EOL | |
+ .' =?'.$this->charset.'?Q?'.$chr; // New line | |
+ $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line | |
} | |
- | |
- // If we're at the character limit, add the line to the output, | |
- // reset our temp variable, and keep on chuggin' | |
- if ((strlen($temp) + strlen($char)) >= $limit) | |
+ else | |
{ | |
- $output .= $temp.$this->crlf; | |
- $temp = ''; | |
+ $output .= $chr; | |
+ $length += $l; | |
} | |
- | |
- // Add the character to our temporary line | |
- $temp .= $char; | |
} | |
- // wrap each line with the shebang, charset, and transfer encoding | |
- // the preceding space on successive lines is required for header "folding" | |
- return trim(preg_replace('/^(.*?)(\r*)$/m', ' =?'.$this->charset.'?Q?$1?=$2', $output.$temp)); | |
+ // End the header | |
+ return $output.'?='; | |
} | |
// -------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment