Translated using Weblate (Portuguese)
[phpmyadmin.git] / src / Encoding.php
blobaec79206fc337a9e394663e5bb8f21a661e741b7
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin;
7 use function array_intersect;
8 use function array_map;
9 use function explode;
10 use function fclose;
11 use function feof;
12 use function fgets;
13 use function fopen;
14 use function function_exists;
15 use function fwrite;
16 use function iconv;
17 use function mb_convert_encoding;
18 use function mb_convert_kana;
19 use function mb_detect_encoding;
20 use function mb_list_encodings;
21 use function strtolower;
22 use function tempnam;
23 use function unlink;
25 /**
26 * Encoding conversion helper class
28 class Encoding
30 /**
31 * None encoding conversion engine
33 public const ENGINE_NONE = 0;
35 /**
36 * iconv encoding conversion engine
38 public const ENGINE_ICONV = 1;
40 /**
41 * mbstring encoding conversion engine
43 public const ENGINE_MB = 3;
45 /**
46 * Chosen encoding engine
48 private static int|null $engine = null;
50 /**
51 * Map of conversion engine configurations
53 * Each entry contains:
55 * - function to detect
56 * - engine contant
57 * - extension name to warn when missing
59 * @var mixed[]
61 private static array $enginemap = [
62 'iconv' => ['iconv', self::ENGINE_ICONV, 'iconv'],
63 'mb' => ['mb_convert_encoding', self::ENGINE_MB, 'mbstring'],
64 'none' => ['isset', self::ENGINE_NONE, ''],
67 /**
68 * Order of automatic detection of engines
70 * @var mixed[]
72 private static array $engineorder = ['iconv', 'mb'];
74 /**
75 * Kanji encodings list
77 private static string $kanjiEncodings = 'ASCII,SJIS,EUC-JP,JIS';
79 /**
80 * Initializes encoding engine detecting available backends.
82 public static function initEngine(): void
84 $engine = 'auto';
85 $config = Config::getInstance();
86 if (isset($config->settings['RecodingEngine'])) {
87 $engine = $config->settings['RecodingEngine'];
90 /* Use user configuration */
91 if (isset(self::$enginemap[$engine])) {
92 if (function_exists(self::$enginemap[$engine][0])) {
93 self::$engine = self::$enginemap[$engine][1];
95 return;
98 Core::warnMissingExtension(self::$enginemap[$engine][2]);
101 /* Autodetection */
102 foreach (self::$engineorder as $engine) {
103 if (function_exists(self::$enginemap[$engine][0])) {
104 self::$engine = self::$enginemap[$engine][1];
106 return;
110 /* Fallback to none conversion */
111 self::$engine = self::ENGINE_NONE;
115 * Setter for engine. Use with caution, mostly useful for testing.
117 * @param int $engine Engine encoding
119 public static function setEngine(int $engine): void
121 self::$engine = $engine;
125 * Checks whether there is any charset conversion supported
127 public static function isSupported(): bool
129 if (self::$engine === null) {
130 self::initEngine();
133 return self::$engine != self::ENGINE_NONE;
137 * Converts encoding of text according to parameters with detected
138 * conversion function.
140 * @param string $srcCharset source charset
141 * @param string $destCharset target charset
142 * @param string $what what to convert
144 * @return string converted text
146 public static function convertString(
147 string $srcCharset,
148 string $destCharset,
149 string $what,
150 ): string {
151 if ($srcCharset === $destCharset) {
152 return $what;
155 if (self::$engine === null) {
156 self::initEngine();
159 return match (self::$engine) {
160 self::ENGINE_ICONV => iconv(
161 $srcCharset,
162 $destCharset . (Config::getInstance()->settings['IconvExtraParams'] ?? ''), $what,
164 self::ENGINE_MB => mb_convert_encoding($what, $destCharset, $srcCharset),
165 default => $what,
170 * Detects whether Kanji encoding is available
172 public static function canConvertKanji(): bool
174 return $GLOBALS['lang'] === 'ja';
178 * Setter for Kanji encodings. Use with caution, mostly useful for testing.
180 public static function getKanjiEncodings(): string
182 return self::$kanjiEncodings;
186 * Setter for Kanji encodings. Use with caution, mostly useful for testing.
188 * @param string $value Kanji encodings list
190 public static function setKanjiEncodings(string $value): void
192 self::$kanjiEncodings = $value;
196 * Reverses SJIS & EUC-JP position in the encoding codes list
198 public static function kanjiChangeOrder(): void
200 $parts = explode(',', self::$kanjiEncodings);
201 if ($parts[1] === 'EUC-JP') {
202 self::$kanjiEncodings = 'ASCII,SJIS,EUC-JP,JIS';
204 return;
207 self::$kanjiEncodings = 'ASCII,EUC-JP,SJIS,JIS';
211 * Kanji string encoding convert
213 * @param string $str the string to convert
214 * @param string $enc the destination encoding code
215 * @param string $kana set 'kana' convert to JIS-X208-kana
217 * @return string the converted string
219 public static function kanjiStrConv(string $str, string $enc, string $kana): string
221 if ($enc === '' && $kana === '') {
222 return $str;
225 $stringEncoding = mb_detect_encoding($str, self::$kanjiEncodings);
226 if ($stringEncoding === false) {
227 $stringEncoding = 'utf-8';
230 if ($kana === 'kana') {
231 $dist = mb_convert_kana($str, 'KV', $stringEncoding);
232 $str = $dist;
235 if ($stringEncoding !== $enc && $enc !== '') {
236 return mb_convert_encoding($str, $enc, $stringEncoding);
239 return $str;
243 * Kanji file encoding convert
245 * @param string $file the name of the file to convert
246 * @param string $enc the destination encoding code
247 * @param string $kana set 'kana' convert to JIS-X208-kana
249 * @return string the name of the converted file
251 public static function kanjiFileConv(string $file, string $enc, string $kana): string
253 if ($enc === '' && $kana === '') {
254 return $file;
257 $tmpfname = (string) tempnam(Config::getInstance()->getUploadTempDir(), $enc);
258 $fpd = fopen($tmpfname, 'wb');
259 if ($fpd === false) {
260 return $file;
263 $fps = fopen($file, 'r');
264 if ($fps === false) {
265 return $file;
268 self::kanjiChangeOrder();
269 while (! feof($fps)) {
270 $line = fgets($fps, 4096);
271 if ($line === false) {
272 continue;
275 $dist = self::kanjiStrConv($line, $enc, $kana);
276 fwrite($fpd, $dist);
279 self::kanjiChangeOrder();
280 fclose($fps);
281 fclose($fpd);
282 unlink($file);
284 return $tmpfname;
288 * Defines radio form fields to switch between encoding modes
290 * @return string HTML code for the radio controls
292 public static function kanjiEncodingForm(): string
294 $template = new Template();
296 return $template->render('encoding/kanji_encoding_form');
300 * Lists available encodings.
302 * @return mixed[]
304 public static function listEncodings(): array
306 if (self::$engine === null) {
307 self::initEngine();
310 /* Most engines do not support listing */
311 $config = Config::getInstance();
312 if (self::$engine != self::ENGINE_MB) {
313 return $config->settings['AvailableCharsets'];
316 return array_intersect(
317 array_map(strtolower(...), mb_list_encodings()),
318 $config->settings['AvailableCharsets'],