From f270a6ebb05f310560d08f207aad52f3eeaf2e26 Mon Sep 17 00:00:00 2001 From: tokul Date: Wed, 3 Aug 2005 12:06:42 +0000 Subject: [PATCH] using B encoding with headers in multibyte character sets. git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@9891 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- functions/mime.php | 121 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 10 deletions(-) diff --git a/functions/mime.php b/functions/mime.php index 8d1cea0a..7e077007 100644 --- a/functions/mime.php +++ b/functions/mime.php @@ -784,16 +784,19 @@ function decodeHeader ($string, $utfencode=true,$htmlsave=true,$decide=false) { * Encodes header * * Function uses XTRA_CODE _encodeheader function, if such function exists. - * - * mb_encode_mimeheader is used, if function is present, 50% or more bytes - * are 8bit and multibyte character set is used. * * Function uses Q encoding by default and encodes a string according to RFC * 1522 for use in headers if it contains 8-bit characters or anything that * looks like it should be encoded. * + * Function switches to B encoding and encodeHeaderBase64() function, if + * string is 8bit and multibyte character set supported by mbstring extension + * is used. It can cause E_USER_NOTICE errors, if interface is used with + * multibyte character set unsupported by mbstring extension. + * * @param string $string header string, that has to be encoded * @return string quoted-printable encoded string + * @todo make $mb_charsets system wide constant */ function encodeHeader ($string) { global $default_charset, $languages, $squirrelmail_language; @@ -804,13 +807,17 @@ function encodeHeader ($string) { } // Use B encoding for multibyte charsets - /* - $mb_charsets = array('utf-8','big-5','gb2313','euc-kr'); - if (function_exists('mb_encode_mimeheader') && - in_array($default_charset,$mb_charsets) && - in_array($default_charset,sq_mb_list_encodings())) { - return mb_encode_mimeheader($string,$default_charset,'B',"\r\n"); - }*/ + $mb_charsets = array('utf-8','big5','gb2313','euc-kr'); + if (in_array($default_charset,$mb_charsets) && + in_array($default_charset,sq_mb_list_encodings()) && + sq_is8bit($string)) { + return encodeHeaderBase64($string,$default_charset); + } elseif (in_array($default_charset,$mb_charsets) && + sq_is8bit($string) && + ! in_array($default_charset,sq_mb_list_encodings())) { + // Add E_USER_NOTICE error here (can cause 'Cannot add header information' warning in compose.php) + // trigger_error('encodeHeader: Multibyte character set unsupported by mbstring extension.',E_USER_NOTICE); + } // Encode only if the string contains 8-bit characters or =? $j = strlen($string); @@ -925,6 +932,100 @@ function encodeHeader ($string) { return $string; } +/** + * Encodes string according to rfc2047 B encoding header formating rules + * + * It is recommended way to encode headers with character sets that store + * symbols in more than one byte. + * + * Function requires mbstring support. If required mbstring functions are missing, + * function returns false and sets E_USER_WARNING level error message. + * + * Minimal requirements - php 4.0.6 with mbstring extension. Please note, + * that mbstring functions will generate E_WARNING errors, if unsupported + * character set is used. mb_encode_mimeheader function provided by php + * mbstring extension is not used in order to get better control of header + * encoding. + * + * Used php code functions - function_exists(), trigger_error(), strlen() + * (is used with charset names and base64 strings). Used php mbstring + * functions - mb_strlen and mb_substr. + * + * Related documents: rfc 2045 (BASE64 encoding), rfc 2047 (mime header + * encoding), rfc 2822 (header folding) + * + * @param string $string header string that must be encoded + * @param string $charset character set. Must be supported by mbstring extension. + * Use sq_mb_list_encodings() to detect supported charsets. + * @return string string encoded according to rfc2047 B encoding formating rules + * @since 1.5.1 + * @todo First header line can be wrapped to $iMaxLength - $HeaderFieldLength - 1 + * @todo Do we want to control max length of header? + * @todo Do we want to control EOL (end-of-line) marker? + * @todo Do we want to translate error message? + */ +function encodeHeaderBase64($string,$charset) { + /** + * Check mbstring function requirements. + */ + if (! function_exists('mb_strlen') || + ! function_exists('mb_substr')) { + // set E_USER_WARNING + trigger_error('encodeHeaderBase64: Required mbstring functions are missing.',E_USER_WARNING); + // return false + return false; + } + + // initial return array + $aRet = array(); + + /** + * header length = 75 symbols max (same as in encodeHeader) + * remove $charset length + * remove =? ? ?= (5 chars) + * remove 2 more chars (\r\n ?) + */ + $iMaxLength = 75 - strlen($charset) - 7; + + // set first character position + $iStartCharNum = 0; + + // loop through all characters. count characters and not bytes. + for ($iCharNum=1; $iCharNum<=mb_strlen($string,$charset); $iCharNum++) { + // encode string from starting character to current character. + $encoded_string = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum,$charset)); + + // Check encoded string length + if(strlen($encoded_string)>$iMaxLength) { + // if string exceeds max length, reduce number of encoded characters and add encoded string part to array + $aRet[] = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum-1,$charset)); + + // set new starting character + $iStartCharNum = $iCharNum-1; + + // encode last char (in case it is last character in string) + $encoded_string = base64_encode(mb_substr($string,$iStartCharNum,$iCharNum-$iStartCharNum,$charset)); + } // if string is shorter than max length - add next character + } + + // add last encoded string to array + $aRet[] = $encoded_string; + + // set initial return string + $sRet = ''; + + // loop through encoded strings + foreach($aRet as $string) { + // TODO: Do we want to control EOL (end-of-line) marker + if ($sRet!='') $sRet.= " "; + + // add header tags and encoded string to return string + $sRet.= '=?'.$charset.'?B?'.$string.'?='; + } + + return $sRet; +} + /* This function trys to locate the entity_id of a specific mime element */ function find_ent_id($id, $message) { for ($i = 0, $ret = ''; $ret == '' && $i < count($message->entities); $i++) { -- 2.25.1