alecpl
2008-09-12 6d89d65cd87e2bea02146a25265e017b7b85ef90
commit | author | age
bdc07a 1 <?php
83dbb7 2 /*
T 3 utf8 1.0
4 Copyright: Left
5 ---------------------------------------------------------------------------------
6 Version:        1.0
7 Date:           23 November 2004
8 ---------------------------------------------------------------------------------
9 Author:         Alexander Minkovsky (a_minkovsky@hotmail.com)
10 ---------------------------------------------------------------------------------
11 License:        Choose the more appropriated for You - I don't care.
12 ---------------------------------------------------------------------------------
13 Description:
14     Class provides functionality to convert single byte strings, such as CP1251
15     ti UTF-8 multibyte format and vice versa.
16     Class loads a concrete charset map, for example CP1251.
17     (Refer to ftp://ftp.unicode.org/Public/MAPPINGS/ for map files)
18     Directory containing MAP files is predefined as constant.
19     Each charset is also predefined as constant pointing to the MAP file.
20 ---------------------------------------------------------------------------------
21 Example usage:
22     Pass the desired charset in the class constructor:
23     $utfConverter = new utf8(CP1251); //defaults to CP1250.
24     or load the charset MAP using loadCharset method like this:
25     $utfConverter->loadCharset(CP1252);
26     Then call
27     $res = $utfConverter->strToUtf8($str);
28     or
29     $res = $utfConverter->utf8ToStr($utf);
30     to get the needed encoding.
31 ---------------------------------------------------------------------------------
32 Note:
33     Rewrite or Override the onError method if needed. It's the error handler used from everywhere and takes 2 parameters:
34     err_code and err_text. By default it just prints out a message about the error.
35 */
36
37 // Charset maps
38 // Adapted to fit RoundCube
39 define("UTF8_MAP_DIR", "program/lib/encoding");
40 $utf8_maps = array(
41   "CP1250" => UTF8_MAP_DIR . "/CP1250.map",
42   "CP1251" => UTF8_MAP_DIR . "/CP1251.map",
43   "CP1252" => UTF8_MAP_DIR . "/CP1252.map",
44   "CP1253" => UTF8_MAP_DIR . "/CP1253.map",
45   "CP1254" => UTF8_MAP_DIR . "/CP1254.map",
46   "CP1255" => UTF8_MAP_DIR . "/CP1255.map",
47   "CP1256" => UTF8_MAP_DIR . "/CP1256.map",
48   "CP1257" => UTF8_MAP_DIR . "/CP1257.map",
49   "CP1258" => UTF8_MAP_DIR . "/CP1258.map",
50   "ISO-8859-1" => UTF8_MAP_DIR . "/ISO-8859-1.map",
51   "ISO-8859-2" => UTF8_MAP_DIR . "/ISO-8859-2.map",
52   "ISO-8859-3" => UTF8_MAP_DIR . "/ISO-8859-3.map",
5f56a5 53   "ISO-8859-4" => UTF8_MAP_DIR . "/ISO-8859-4.map",
T 54   "ISO-8859-5" => UTF8_MAP_DIR . "/ISO-8859-5.map",
55   "ISO-8859-6" => UTF8_MAP_DIR . "/ISO-8859-6.map",
56   "ISO-8859-7" => UTF8_MAP_DIR . "/ISO-8859-7.map",
57   "ISO-8859-8" => UTF8_MAP_DIR . "/ISO-8859-8.map",
515b0c 58   "ISO-8859-9" => UTF8_MAP_DIR . "/ISO-8859-9.map",
T 59   "KOI8-R" => UTF8_MAP_DIR . "/KOI8R.map",
60   "KOI8R" => UTF8_MAP_DIR . "/KOI8R.map"
5f56a5 61   );
83dbb7 62
T 63 //Error constants
64 define("ERR_OPEN_MAP_FILE","ERR_OPEN_MAP_FILE");
65
66 //Class definition
67 Class utf8{
68
58e360 69   var $charset = "ISO-8859-1";
83dbb7 70   var $ascMap = array();
T 71   var $utfMap = array();
58e360 72
83dbb7 73   function __construct($charset="ISO-8859-1"){
T 74     $this->loadCharset($charset);
75   }
76   
77   //Load charset
78   function loadCharset($charset){
79     global $utf8_maps;
58e360 80
83dbb7 81     if (!is_file($utf8_maps[$charset]))
T 82       {
83       $this->onError(ERR_OPEN_MAP_FILE, "Failed to open map file for $charset");
84       return;
85       }
86     
87     if (empty($this->ascMap[$charset]))
88       {
89       $lines = file_get_contents($utf8_maps[$charset]);
90       $lines = preg_replace("/#.*$/m","",$lines);
91       $lines = preg_replace("/\n\n/","",$lines);
92       $lines = explode("\n",$lines);
93       foreach($lines as $line){
94         $parts = explode('0x',$line);
95         if(count($parts)==3){
96           $asc=hexdec(substr($parts[1],0,2));
97           $utf=hexdec(substr($parts[2],0,4));
98           $this->ascMap[$charset][$asc]=$utf;
99         }
100       }
101     }
102     
103     $this->charset = $charset;
104     $this->utfMap = array_flip($this->ascMap[$charset]);
105   }
106
107   //Error handler
108   function onError($err_code,$err_text){
109     //print($err_code . " : " . $err_text . "<hr>\n");
110     raise_error(array('code' => 500,
111                       'file' => __FILE__,
112                       'message' => $err_text), TRUE, FALSE);
113   }
114
115   //Translate string ($str) to UTF-8 from given charset
116   function strToUtf8($str){
117     $chars = unpack('C*', $str);
118     $cnt = count($chars);
119     for($i=1;$i<=$cnt;$i++) $this->_charToUtf8($chars[$i]);
120     return implode("",$chars);
121   }
122
123   //Translate UTF-8 string to single byte string in the given charset
124   function utf8ToStr($utf){
125     $chars = unpack('C*', $utf);
126     $cnt = count($chars);
127     $res = ""; //No simple way to do it in place... concatenate char by char
128     for ($i=1;$i<=$cnt;$i++){
129       $res .= $this->_utf8ToChar($chars, $i);
130     }
131     return $res;
132   }
133
134   //Char to UTF-8 sequence
135   function _charToUtf8(&$char){
136     $c = (int)$this->ascMap[$this->charset][$char];
137     if ($c < 0x80){
138       $char = chr($c);
139     }
140     else if($c<0x800) // 2 bytes
141       $char = (chr(0xC0 | $c>>6) . chr(0x80 | $c & 0x3F));
142     else if($c<0x10000) // 3 bytes
143       $char = (chr(0xE0 | $c>>12) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F));
144     else if($c<0x200000) // 4 bytes
145       $char = (chr(0xF0 | $c>>18) . chr(0x80 | $c>>12 & 0x3F) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F));
146   }
147
148   //UTF-8 sequence to single byte character
149   function _utf8ToChar(&$chars, &$idx){
150     if(($chars[$idx] >= 240) && ($chars[$idx] <= 255)){ // 4 bytes
151       $utf =    (intval($chars[$idx]-240)   << 18) +
152                 (intval($chars[++$idx]-128) << 12) +
153                 (intval($chars[++$idx]-128) << 6) +
154                 (intval($chars[++$idx]-128) << 0);
155     }
156     else if (($chars[$idx] >= 224) && ($chars[$idx] <= 239)){ // 3 bytes
157       $utf =    (intval($chars[$idx]-224)   << 12) +
158                 (intval($chars[++$idx]-128) << 6) +
159                 (intval($chars[++$idx]-128) << 0);
160     }
161     else if (($chars[$idx] >= 192) && ($chars[$idx] <= 223)){ // 2 bytes
162       $utf =    (intval($chars[$idx]-192)   << 6) +
163                 (intval($chars[++$idx]-128) << 0);
164     }
165     else{ // 1 byte
166       $utf = $chars[$idx];
167     }
168     if(array_key_exists($utf,$this->utfMap))
169       return chr($this->utfMap[$utf]);
170     else
171       return "?";
172   }
173
174 }
58e360 175
T 176 ?>