PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/Encoding.php

https://gitlab.com/trungthao379/phpmyadmin
PHP | 327 lines | 168 code | 27 blank | 132 comment | 32 complexity | 907e785c46d787f83781169bcde9a645 MD5 | raw file
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Hold the PMA\libraries\Encoding class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. namespace PMA\libraries;
  9. /**
  10. * Encoding conversion helper class
  11. *
  12. * @package PhpMyAdmin
  13. */
  14. class Encoding
  15. {
  16. /**
  17. * None encoding conversion engine
  18. *
  19. * @var int
  20. */
  21. const ENGINE_NONE = 0;
  22. /**
  23. * iconv encoding conversion engine
  24. *
  25. * @var int
  26. */
  27. const ENGINE_ICONV = 1;
  28. /**
  29. * recode encoding conversion engine
  30. *
  31. * @var int
  32. */
  33. const ENGINE_RECODE = 2;
  34. /**
  35. * mbstring encoding conversion engine
  36. *
  37. * @var int
  38. */
  39. const ENGINE_MB = 3;
  40. /**
  41. * Chosen encoding engine
  42. *
  43. * @var int
  44. */
  45. private static $_engine = null;
  46. /**
  47. * Map of conversion engine configurations
  48. *
  49. * Each entry contains:
  50. *
  51. * - function to detect
  52. * - engine contant
  53. * - extension name to warn when missing
  54. *
  55. * @var array
  56. */
  57. private static $_enginemap = array(
  58. 'iconv' => array('iconv', self::ENGINE_ICONV, 'iconv'),
  59. 'recode' => array('recode_string', self::ENGINE_RECODE, 'recode'),
  60. 'mb' => array('mb_convert_encoding', self::ENGINE_MB, 'mbstring'),
  61. 'none' => array('isset', self::ENGINE_NONE, ''),
  62. );
  63. /**
  64. * Order of automatic detection of engines
  65. *
  66. * @var array
  67. */
  68. private static $_engineorder = array(
  69. 'mb', 'iconv', 'recode',
  70. );
  71. /**
  72. * Kanji encodings list
  73. *
  74. * @var string
  75. */
  76. private static $_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS';
  77. /**
  78. * Initializes encoding engine detecting available backends.
  79. *
  80. * @return void
  81. */
  82. public static function initEngine()
  83. {
  84. $engine = 'auto';
  85. if (isset($GLOBALS['cfg']['RecodingEngine'])) {
  86. $engine = $GLOBALS['cfg']['RecodingEngine'];
  87. }
  88. /* Use user configuration */
  89. if (isset(self::$_enginemap[$engine])) {
  90. if (@function_exists(self::$_enginemap[$engine][0])) {
  91. self::$_engine = self::$_enginemap[$engine][1];
  92. return;
  93. } else {
  94. PMA_warnMissingExtension(self::$_enginemap[$engine][2]);
  95. }
  96. }
  97. /* Autodetection */
  98. foreach (self::$_engineorder as $engine) {
  99. if (@function_exists(self::$_enginemap[$engine][0])) {
  100. self::$_engine = self::$_enginemap[$engine][1];
  101. return;
  102. }
  103. }
  104. /* Fallback to none conversion */
  105. self::$_engine = self::ENGINE_NONE;
  106. }
  107. /**
  108. * Setter for engine. Use with caution, mostly useful for testing.
  109. *
  110. * @return void
  111. */
  112. public static function setEngine($engine)
  113. {
  114. self::$_engine = $engine;
  115. }
  116. /**
  117. * Checks whether there is any charset conversion supported
  118. *
  119. * @return bool
  120. */
  121. public static function isSupported()
  122. {
  123. if (is_null(self::$_engine)) {
  124. self::initEngine();
  125. }
  126. return self::$_engine != self::ENGINE_NONE;
  127. }
  128. /**
  129. * Converts encoding of text according to parameters with detected
  130. * conversion function.
  131. *
  132. * @param string $src_charset source charset
  133. * @param string $dest_charset target charset
  134. * @param string $what what to convert
  135. *
  136. * @return string converted text
  137. *
  138. * @access public
  139. */
  140. public static function convertString($src_charset, $dest_charset, $what)
  141. {
  142. if ($src_charset == $dest_charset) {
  143. return $what;
  144. }
  145. if (is_null(self::$_engine)) {
  146. self::initEngine();
  147. }
  148. switch (self::$_engine) {
  149. case self::ENGINE_RECODE:
  150. return recode_string(
  151. $src_charset . '..' . $dest_charset,
  152. $what
  153. );
  154. case self::ENGINE_ICONV:
  155. return iconv(
  156. $src_charset,
  157. $dest_charset .
  158. (isset($GLOBALS['cfg']['IconvExtraParams']) ? $GLOBALS['cfg']['IconvExtraParams'] : ''),
  159. $what
  160. );
  161. case self::ENGINE_MB:
  162. return mb_convert_encoding(
  163. $what,
  164. $dest_charset,
  165. $src_charset
  166. );
  167. default:
  168. return $what;
  169. }
  170. }
  171. /**
  172. * Detects whether Kanji encoding is available
  173. *
  174. * @return bool
  175. */
  176. public static function canConvertKanji()
  177. {
  178. return (
  179. $GLOBALS['lang'] == 'ja' &&
  180. function_exists('mb_convert_encoding')
  181. );
  182. }
  183. /**
  184. * Setter for Kanji encodings. Use with caution, mostly useful for testing.
  185. *
  186. * @return string
  187. */
  188. public static function getKanjiEncodings()
  189. {
  190. return self::$_kanji_encodings;
  191. }
  192. /**
  193. * Setter for Kanji encodings. Use with caution, mostly useful for testing.
  194. *
  195. * @return void
  196. */
  197. public static function setKanjiEncodings($value)
  198. {
  199. self::$_kanji_encodings = $value;
  200. }
  201. /**
  202. * Reverses SJIS & EUC-JP position in the encoding codes list
  203. *
  204. * @return void
  205. */
  206. public static function kanjiChangeOrder()
  207. {
  208. $parts = explode(',', self::$_kanji_encodings);
  209. if ($parts[1] == 'EUC-JP') {
  210. self::$_kanji_encodings = 'ASCII,SJIS,EUC-JP,JIS';
  211. } else {
  212. self::$_kanji_encodings = 'ASCII,EUC-JP,SJIS,JIS';
  213. }
  214. }
  215. /**
  216. * Kanji string encoding convert
  217. *
  218. * @param string $str the string to convert
  219. * @param string $enc the destination encoding code
  220. * @param string $kana set 'kana' convert to JIS-X208-kana
  221. *
  222. * @return string the converted string
  223. */
  224. public static function kanjiStrConv($str, $enc, $kana)
  225. {
  226. if ($enc == '' && $kana == '') {
  227. return $str;
  228. }
  229. $string_encoding = mb_detect_encoding($str, self::$_kanji_encodings);
  230. if ($string_encoding === false) {
  231. $string_encoding = 'utf-8';
  232. }
  233. if ($kana == 'kana') {
  234. $dist = mb_convert_kana($str, 'KV', $string_encoding);
  235. $str = $dist;
  236. }
  237. if ($string_encoding != $enc && $enc != '') {
  238. $dist = mb_convert_encoding($str, $enc, $string_encoding);
  239. } else {
  240. $dist = $str;
  241. }
  242. return $dist;
  243. }
  244. /**
  245. * Kanji file encoding convert
  246. *
  247. * @param string $file the name of the file to convert
  248. * @param string $enc the destination encoding code
  249. * @param string $kana set 'kana' convert to JIS-X208-kana
  250. *
  251. * @return string the name of the converted file
  252. */
  253. public static function kanjiFileConv($file, $enc, $kana)
  254. {
  255. if ($enc == '' && $kana == '') {
  256. return $file;
  257. }
  258. $tmpfname = tempnam('', $enc);
  259. $fpd = fopen($tmpfname, 'wb');
  260. $fps = fopen($file, 'r');
  261. self::kanjiChangeOrder();
  262. while (!feof($fps)) {
  263. $line = fgets($fps, 4096);
  264. $dist = self::kanjiStrConv($line, $enc, $kana);
  265. fputs($fpd, $dist);
  266. } // end while
  267. self::kanjiChangeOrder();
  268. fclose($fps);
  269. fclose($fpd);
  270. unlink($file);
  271. return $tmpfname;
  272. }
  273. /**
  274. * Defines radio form fields to switch between encoding modes
  275. *
  276. * @return string xhtml code for the radio controls
  277. */
  278. public static function kanjiEncodingForm()
  279. {
  280. return '<ul><li>'
  281. . '<input type="radio" name="knjenc" value="" checked="checked" '
  282. . 'id="kj-none" />'
  283. . '<label for="kj-none">'
  284. /* l10n: This is currently used only in Japanese locales */
  285. . _pgettext('None encoding conversion', 'None')
  286. . '</label>'
  287. . '<input type="radio" name="knjenc" value="EUC-JP" id="kj-euc" />'
  288. . '<label for="kj-euc">EUC</label>'
  289. . '<input type="radio" name="knjenc" value="SJIS" id="kj-sjis" />'
  290. . '<label for="kj-sjis">SJIS</label>'
  291. . '</li>'
  292. . '<li>'
  293. . '<input type="checkbox" name="xkana" value="kana" id="kj-kana" />'
  294. . '<label for="kj-kana">'
  295. /* l10n: This is currently used only in Japanese locales */
  296. . __('Convert to Kana')
  297. . '</label><br />'
  298. . '</li></ul>';
  299. }
  300. }