1 <?php 2 /** 3 * Originally based on code: 4 * 5 * Copyright (C) 2000 Edmund Grimley Evans <edmundo@rano.org> 6 * Released under the GPL (version 2) 7 * 8 * Translated from C to PHP by Thomas Bruederli <roundcube@gmail.com> 9 * Code extracted from the RoundCube Webmail (http://roundcube.net) project, 10 * SVN revision 1757 11 * The RoundCube project is released under the GPL (version 2) 12 * 13 * Copyright 2008-2017 Horde LLC (http://www.horde.org/) 14 * 15 * See the enclosed file LICENSE for license information (LGPL). If you 16 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 17 * 18 * @category Horde 19 * @copyright 2000 Edmund Grimley Evans <edmundo@rano.org> 20 * @copyright 2008-2017 Horde LLC 21 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 22 * @package Imap_Client 23 */ 24 25 /** 26 * Allows conversions between UTF-8 and UTF7-IMAP (RFC 3501 [5.1.3]). 27 * 28 * @author Michael Slusarz <slusarz@horde.org> 29 * @category Horde 30 * @copyright 2000 Edmund Grimley Evans <edmundo@rano.org> 31 * @copyright 2008-2017 Horde LLC 32 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 33 * @package Imap_Client 34 */ 35 class Horde_Imap_Client_Utf7imap 36 { 37 /** 38 * Lookup table for conversion. 39 * 40 * @var array 41 */ 42 private static $_index64 = array( 43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 45 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, 63, -1, -1, -1, 46 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 47 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 48 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 49 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 50 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 51 ); 52 53 /** 54 * Lookup table for conversion. 55 * 56 * @var array 57 */ 58 private static $_base64 = array( 59 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 60 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 61 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 62 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', 63 '4', '5', '6', '7', '8', '9', '+', ',' 64 ); 65 66 /** 67 * Is mbstring extension available? 68 * 69 * @var array 70 */ 71 protected static $_mbstring = null; 72 73 /** 74 * Convert a string from UTF7-IMAP to UTF-8. 75 * 76 * @param string $str The UTF7-IMAP string. 77 * 78 * @return string The converted UTF-8 string. 79 * @throws Horde_Imap_Client_Exception 80 */ 81 public static function Utf7ImapToUtf8($str) 82 { 83 if ($str instanceof Horde_Imap_Client_Mailbox) { 84 return $str->utf8; 85 } 86 87 $str = strval($str); 88 89 /* Try mbstring, if available, which should be faster. Don't use the 90 * IMAP utf7_* functions because they are known to be buggy. */ 91 if (is_null(self::$_mbstring)) { 92 self::$_mbstring = extension_loaded('mbstring'); 93 } 94 if (self::$_mbstring) { 95 return @mb_convert_encoding($str, 'UTF-8', 'UTF7-IMAP'); 96 } 97 98 $p = ''; 99 $ptr = &self::$_index64; 100 101 for ($i = 0, $u7len = strlen($str); $u7len > 0; ++$i, --$u7len) { 102 $u7 = $str[$i]; 103 if ($u7 === '&') { 104 $u7 = $str[++$i]; 105 if (--$u7len && ($u7 === '-')) { 106 $p .= '&'; 107 continue; 108 } 109 110 $ch = 0; 111 $k = 10; 112 for (; $u7len > 0; ++$i, --$u7len) { 113 $u7 = $str[$i]; 114 115 if ((ord($u7) & 0x80) || ($b = $ptr[ord($u7)]) === -1) { 116 break; 117 } 118 119 if ($k > 0) { 120 $ch |= $b << $k; 121 $k -= 6; 122 } else { 123 $ch |= $b >> (-$k); 124 if ($ch < 0x80) { 125 /* Printable US-ASCII */ 126 if ((0x20 <= $ch) && ($ch < 0x7f)) { 127 throw new Horde_Imap_Client_Exception( 128 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 129 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 130 ); 131 } 132 $p .= chr($ch); 133 } else if ($ch < 0x800) { 134 $p .= chr(0xc0 | ($ch >> 6)) . 135 chr(0x80 | ($ch & 0x3f)); 136 } else { 137 $p .= chr(0xe0 | ($ch >> 12)) . 138 chr(0x80 | (($ch >> 6) & 0x3f)) . 139 chr(0x80 | ($ch & 0x3f)); 140 } 141 142 $ch = ($b << (16 + $k)) & 0xffff; 143 $k += 10; 144 } 145 } 146 147 /* Non-zero or too many extra bits -OR- 148 * Base64 not properly terminated -OR- 149 * Adjacent Base64 sections. */ 150 if (($ch || ($k < 6)) || 151 (!$u7len || $u7 !== '-') || 152 (($u7len > 2) && 153 ($str[$i + 1] === '&') && 154 ($str[$i + 2] !== '-'))) { 155 throw new Horde_Imap_Client_Exception( 156 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 157 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 158 ); 159 } 160 } elseif ((ord($u7) < 0x20) || (ord($u7) >= 0x7f)) { 161 /* Not printable US-ASCII */ 162 throw new Horde_Imap_Client_Exception( 163 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 164 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 165 ); 166 } else { 167 $p .= $u7; 168 } 169 } 170 171 return $p; 172 } 173 174 /** 175 * Convert a string from UTF-8 to UTF7-IMAP. 176 * 177 * @param string $str The UTF-8 string. 178 * @param boolean $force Assume $str is UTF-8 (no-autodetection)? If 179 * false, attempts to auto-detect if string is 180 * already in UTF7-IMAP. 181 * 182 * @return string The converted UTF7-IMAP string. 183 * @throws Horde_Imap_Client_Exception 184 */ 185 public static function Utf8ToUtf7Imap($str, $force = true) 186 { 187 if ($str instanceof Horde_Imap_Client_Mailbox) { 188 return $str->utf7imap; 189 } 190 191 $str = strval($str); 192 193 /* No need to do conversion if all chars are in US-ASCII range or if 194 * no ampersand is present. But will assume that an already encoded 195 * ampersand means string is in UTF7-IMAP already. */ 196 if (!$force && 197 !preg_match('/[\x80-\xff]|&$|&(?![,+A-Za-z0-9]*-)/', $str)) { 198 return $str; 199 } 200 201 /* Try mbstring, if available, which should be faster. Don't use the 202 * IMAP utf7_* functions because they are known to be buggy. */ 203 if (is_null(self::$_mbstring)) { 204 self::$_mbstring = extension_loaded('mbstring'); 205 } 206 if (self::$_mbstring) { 207 return @mb_convert_encoding($str, 'UTF7-IMAP', 'UTF-8'); 208 } 209 210 $u8len = strlen($str); 211 $i = 0; 212 $base64 = false; 213 $p = ''; 214 $ptr = &self::$_base64; 215 216 while ($u8len) { 217 $u8 = $str[$i]; 218 $c = ord($u8); 219 220 if ($c < 0x80) { 221 $ch = $c; 222 $n = 0; 223 } elseif ($c < 0xc2) { 224 throw new Horde_Imap_Client_Exception( 225 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 226 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 227 ); 228 } elseif ($c < 0xe0) { 229 $ch = $c & 0x1f; 230 $n = 1; 231 } elseif ($c < 0xf0) { 232 $ch = $c & 0x0f; 233 $n = 2; 234 } elseif ($c < 0xf8) { 235 $ch = $c & 0x07; 236 $n = 3; 237 } elseif ($c < 0xfc) { 238 $ch = $c & 0x03; 239 $n = 4; 240 } elseif ($c < 0xfe) { 241 $ch = $c & 0x01; 242 $n = 5; 243 } else { 244 throw new Horde_Imap_Client_Exception( 245 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 246 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 247 ); 248 } 249 250 if ($n > --$u8len) { 251 throw new Horde_Imap_Client_Exception( 252 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 253 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 254 ); 255 } 256 257 ++$i; 258 259 for ($j = 0; $j < $n; ++$j) { 260 $o = ord($str[$i + $j]); 261 if (($o & 0xc0) !== 0x80) { 262 throw new Horde_Imap_Client_Exception( 263 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 264 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 265 ); 266 } 267 $ch = ($ch << 6) | ($o & 0x3f); 268 } 269 270 if (($n > 1) && !($ch >> ($n * 5 + 1))) { 271 throw new Horde_Imap_Client_Exception( 272 Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), 273 Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION 274 ); 275 } 276 277 $i += $n; 278 $u8len -= $n; 279 280 if (($ch < 0x20) || ($ch >= 0x7f)) { 281 if (!$base64) { 282 $p .= '&'; 283 $base64 = true; 284 $b = 0; 285 $k = 10; 286 } 287 288 if ($ch & ~0xffff) { 289 $ch = 0xfffe; 290 } 291 292 $p .= $ptr[($b | $ch >> $k)]; 293 $k -= 6; 294 for (; $k >= 0; $k -= 6) { 295 $p .= $ptr[(($ch >> $k) & 0x3f)]; 296 } 297 298 $b = ($ch << (-$k)) & 0x3f; 299 $k += 16; 300 } else { 301 if ($base64) { 302 if ($k > 10) { 303 $p .= $ptr[$b]; 304 } 305 $p .= '-'; 306 $base64 = false; 307 } 308 309 $p .= chr($ch); 310 if (chr($ch) === '&') { 311 $p .= '-'; 312 } 313 } 314 } 315 316 if ($base64) { 317 if ($k > 10) { 318 $p .= $ptr[$b]; 319 } 320 $p .= '-'; 321 } 322 323 return $p; 324 } 325 326 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body