123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- <?php
- /* vim: set expandtab sw=4 ts=4 sts=4: */
- /**
- * MySQL charset metadata and manipulations
- *
- * @package PhpMyAdmin
- */
- namespace PhpMyAdmin;
- use PhpMyAdmin\DatabaseInterface;
- use PhpMyAdmin\Util;
- /**
- * Class used to manage MySQL charsets
- *
- * @package PhpMyAdmin
- */
- class Charsets
- {
- /**
- * MySQL charsets map
- *
- * @var array
- */
- public static $mysql_charset_map = array(
- 'big5' => 'big5',
- 'cp-866' => 'cp866',
- 'euc-jp' => 'ujis',
- 'euc-kr' => 'euckr',
- 'gb2312' => 'gb2312',
- 'gbk' => 'gbk',
- 'iso-8859-1' => 'latin1',
- 'iso-8859-2' => 'latin2',
- 'iso-8859-7' => 'greek',
- 'iso-8859-8' => 'hebrew',
- 'iso-8859-8-i' => 'hebrew',
- 'iso-8859-9' => 'latin5',
- 'iso-8859-13' => 'latin7',
- 'iso-8859-15' => 'latin1',
- 'koi8-r' => 'koi8r',
- 'shift_jis' => 'sjis',
- 'tis-620' => 'tis620',
- 'utf-8' => 'utf8',
- 'windows-1250' => 'cp1250',
- 'windows-1251' => 'cp1251',
- 'windows-1252' => 'latin1',
- 'windows-1256' => 'cp1256',
- 'windows-1257' => 'cp1257',
- );
- private static $_charsets = array();
- /**
- * The charset for the server
- *
- * @var string
- */
- private static $_charset_server;
- private static $_charsets_descriptions = array();
- private static $_collations = array();
- private static $_default_collations = array();
- /**
- * Loads charset data from the MySQL server.
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return void
- */
- private static function loadCharsets(DatabaseInterface $dbi, $disableIs)
- {
- /* Data already loaded */
- if (count(self::$_charsets) > 0) {
- return;
- }
- if ($disableIs) {
- $sql = 'SHOW CHARACTER SET';
- } else {
- $sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
- . ' `DESCRIPTION` AS `Description`'
- . ' FROM `information_schema`.`CHARACTER_SETS`';
- }
- $res = $dbi->query($sql);
- self::$_charsets = array();
- while ($row = $dbi->fetchAssoc($res)) {
- $name = $row['Charset'];
- self::$_charsets[] = $name;
- self::$_charsets_descriptions[$name] = $row['Description'];
- }
- $dbi->freeResult($res);
- sort(self::$_charsets, SORT_STRING);
- }
- /**
- * Loads collation data from the MySQL server.
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return void
- */
- private static function loadCollations(DatabaseInterface $dbi, $disableIs)
- {
- /* Data already loaded */
- if (count(self::$_collations) > 0) {
- return;
- }
- if ($disableIs) {
- $sql = 'SHOW COLLATION';
- } else {
- $sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
- . ' `COLLATION_NAME` AS `Collation`, `IS_DEFAULT` AS `Default`'
- . ' FROM `information_schema`.`COLLATIONS`';
- }
- $res = $dbi->query($sql);
- while ($row = $dbi->fetchAssoc($res)) {
- $char_set_name = $row['Charset'];
- $name = $row['Collation'];
- self::$_collations[$char_set_name][] = $name;
- if ($row['Default'] == 'Yes' || $row['Default'] == '1') {
- self::$_default_collations[$char_set_name] = $name;
- }
- }
- $dbi->freeResult($res);
- foreach (self::$_collations as $key => $value) {
- sort(self::$_collations[$key], SORT_STRING);
- }
- }
- /**
- * Get current MySQL server charset.
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- *
- * @return string
- */
- public static function getServerCharset(DatabaseInterface $dbi)
- {
- if (self::$_charset_server) {
- return self::$_charset_server;
- } else {
- $charsetServer = $dbi->getVariable('character_set_server');
- if (! is_string($charsetServer)) {// MySQL 5.7.8 fallback, issue #15614
- $charsetServer = $dbi->fetchValue("SELECT @@character_set_server;");
- }
- self::$_charset_server = $charsetServer;
- return self::$_charset_server;
- }
- }
- /**
- * Get MySQL charsets
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return array
- */
- public static function getMySQLCharsets(DatabaseInterface $dbi, $disableIs)
- {
- self::loadCharsets($dbi, $disableIs);
- return self::$_charsets;
- }
- /**
- * Get MySQL charsets descriptions
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return array
- */
- public static function getMySQLCharsetsDescriptions(DatabaseInterface $dbi, $disableIs)
- {
- self::loadCharsets($dbi, $disableIs);
- return self::$_charsets_descriptions;
- }
- /**
- * Get MySQL collations
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return array
- */
- public static function getMySQLCollations(DatabaseInterface $dbi, $disableIs)
- {
- self::loadCollations($dbi, $disableIs);
- return self::$_collations;
- }
- /**
- * Get MySQL default collations
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- *
- * @return array
- */
- public static function getMySQLCollationsDefault(DatabaseInterface $dbi, $disableIs)
- {
- self::loadCollations($dbi, $disableIs);
- return self::$_default_collations;
- }
- /**
- * Generate charset dropdown box
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- * @param string $name Element name
- * @param string $id Element id
- * @param null|string $default Default value
- * @param bool $label Label
- * @param bool $submitOnChange Submit on change
- *
- * @return string
- */
- public static function getCharsetDropdownBox(
- DatabaseInterface $dbi,
- $disableIs,
- $name = null,
- $id = null,
- $default = null,
- $label = true,
- $submitOnChange = false
- ) {
- self::loadCharsets($dbi, $disableIs);
- if (empty($name)) {
- $name = 'character_set';
- }
- $return_str = '<select lang="en" dir="ltr" name="'
- . htmlspecialchars($name) . '"'
- . (empty($id) ? '' : ' id="' . htmlspecialchars($id) . '"')
- . ($submitOnChange ? ' class="autosubmit"' : '') . '>' . "\n";
- if ($label) {
- $return_str .= '<option value="">'
- . __('Charset')
- . '</option>' . "\n";
- }
- $return_str .= '<option value=""></option>' . "\n";
- foreach (self::$_charsets as $current_charset) {
- $current_cs_descr
- = empty(self::$_charsets_descriptions[$current_charset])
- ? $current_charset
- : self::$_charsets_descriptions[$current_charset];
- $return_str .= '<option value="' . $current_charset
- . '" title="' . $current_cs_descr . '"'
- . ($default == $current_charset ? ' selected="selected"' : '') . '>'
- . $current_charset . '</option>' . "\n";
- }
- $return_str .= '</select>' . "\n";
- return $return_str;
- }
- /**
- * Generate collation dropdown box
- *
- * @param DatabaseInterface $dbi DatabaseInterface instance
- * @param boolean $disableIs Disable use of INFORMATION_SCHEMA
- * @param string $name Element name
- * @param string $id Element id
- * @param null|string $default Default value
- * @param bool $label Label
- * @param bool $submitOnChange Submit on change
- *
- * @return string
- */
- public static function getCollationDropdownBox(
- DatabaseInterface $dbi,
- $disableIs,
- $name = null,
- $id = null,
- $default = null,
- $label = true,
- $submitOnChange = false
- ) {
- self::loadCharsets($dbi, $disableIs);
- self::loadCollations($dbi, $disableIs);
- if (empty($name)) {
- $name = 'collation';
- }
- $return_str = '<select lang="en" dir="ltr" name="'
- . htmlspecialchars($name) . '"'
- . (empty($id) ? '' : ' id="' . htmlspecialchars($id) . '"')
- . ($submitOnChange ? ' class="autosubmit"' : '') . '>' . "\n";
- if ($label) {
- $return_str .= '<option value="">'
- . __('Collation')
- . '</option>' . "\n";
- }
- $return_str .= '<option value=""></option>' . "\n";
- foreach (self::$_charsets as $current_charset) {
- $current_cs_descr
- = empty(self::$_charsets_descriptions[$current_charset])
- ? $current_charset
- : self::$_charsets_descriptions[$current_charset];
- $return_str .= '<optgroup label="' . $current_charset
- . '" title="' . $current_cs_descr . '">' . "\n";
- foreach (self::$_collations[$current_charset] as $current_collation) {
- $return_str .= '<option value="' . $current_collation
- . '" title="' . self::getCollationDescr($current_collation) . '"'
- . ($default == $current_collation ? ' selected="selected"' : '')
- . '>'
- . $current_collation . '</option>' . "\n";
- }
- $return_str .= '</optgroup>' . "\n";
- }
- $return_str .= '</select>' . "\n";
- return $return_str;
- }
- /**
- * Returns description for given collation
- *
- * @param string $collation MySQL collation string
- *
- * @return string collation description
- */
- public static function getCollationDescr($collation)
- {
- $parts = explode('_', $collation);
- $name = __('Unknown');
- $variant = null;
- $suffixes = array();
- $unicode = false;
- $unknown = false;
- $level = 0;
- foreach ($parts as $part) {
- if ($level == 0) {
- /* Next will be language */
- $level = 1;
- /* First should be charset */
- switch ($part) {
- case 'binary':
- $name = _pgettext('Collation', 'Binary');
- break;
- // Unicode charsets
- case 'utf8mb4':
- $variant = 'UCA 4.0.0';
- // Fall through to other unicode
- case 'ucs2':
- case 'utf8':
- case 'utf16':
- case 'utf16le':
- case 'utf16be':
- case 'utf32':
- $name = _pgettext('Collation', 'Unicode');
- $unicode = true;
- break;
- // West European charsets
- case 'ascii':
- case 'cp850':
- case 'dec8':
- case 'hp8':
- case 'latin1':
- case 'macroman':
- $name = _pgettext('Collation', 'West European');
- break;
- // Central European charsets
- case 'cp1250':
- case 'cp852':
- case 'latin2':
- case 'macce':
- $name = _pgettext('Collation', 'Central European');
- break;
- // Russian charsets
- case 'cp866':
- case 'koi8r':
- $name = _pgettext('Collation', 'Russian');
- break;
- // Chinese charsets
- case 'gb2312':
- case 'gbk':
- $name = _pgettext('Collation', 'Simplified Chinese');
- break;
- case 'big5':
- $name = _pgettext('Collation', 'Traditional Chinese');
- break;
- case 'gb18030':
- $name = _pgettext('Collation', 'Chinese');
- $unicode = true;
- break;
- // Japanese charsets
- case 'sjis':
- case 'ujis':
- case 'cp932':
- case 'eucjpms':
- $name = _pgettext('Collation', 'Japanese');
- break;
- // Baltic charsets
- case 'cp1257':
- case 'latin7':
- $name = _pgettext('Collation', 'Baltic');
- break;
- // Other
- case 'armscii8':
- case 'armscii':
- $name = _pgettext('Collation', 'Armenian');
- break;
- case 'cp1251':
- $name = _pgettext('Collation', 'Cyrillic');
- break;
- case 'cp1256':
- $name = _pgettext('Collation', 'Arabic');
- break;
- case 'euckr':
- $name = _pgettext('Collation', 'Korean');
- break;
- case 'hebrew':
- $name = _pgettext('Collation', 'Hebrew');
- break;
- case 'geostd8':
- $name = _pgettext('Collation', 'Georgian');
- break;
- case 'greek':
- $name = _pgettext('Collation', 'Greek');
- break;
- case 'keybcs2':
- $name = _pgettext('Collation', 'Czech-Slovak');
- break;
- case 'koi8u':
- $name = _pgettext('Collation', 'Ukrainian');
- break;
- case 'latin5':
- $name = _pgettext('Collation', 'Turkish');
- break;
- case 'swe7':
- $name = _pgettext('Collation', 'Swedish');
- break;
- case 'tis620':
- $name = _pgettext('Collation', 'Thai');
- break;
- default:
- $name = _pgettext('Collation', 'Unknown');
- $unknown = true;
- break;
- }
- continue;
- }
- if ($level == 1) {
- /* Next will be variant unless changed later */
- $level = 4;
- /* Locale name or code */
- $found = true;
- switch ($part) {
- case 'general':
- break;
- case 'bulgarian':
- case 'bg':
- $name = _pgettext('Collation', 'Bulgarian');
- break;
- case 'chinese':
- case 'cn':
- case 'zh':
- if ($unicode) {
- $name = _pgettext('Collation', 'Chinese');
- }
- break;
- case 'croatian':
- case 'hr':
- $name = _pgettext('Collation', 'Croatian');
- break;
- case 'czech':
- case 'cs':
- $name = _pgettext('Collation', 'Czech');
- break;
- case 'danish':
- case 'da':
- $name = _pgettext('Collation', 'Danish');
- break;
- case 'english':
- case 'en':
- $name = _pgettext('Collation', 'English');
- break;
- case 'esperanto':
- case 'eo':
- $name = _pgettext('Collation', 'Esperanto');
- break;
- case 'estonian':
- case 'et':
- $name = _pgettext('Collation', 'Estonian');
- break;
- case 'german1':
- $name = _pgettext('Collation', 'German (dictionary order)');
- break;
- case 'german2':
- $name = _pgettext('Collation', 'German (phone book order)');
- break;
- case 'german':
- case 'de':
- /* Name is set later */
- $level = 2;
- break;
- case 'hungarian':
- case 'hu':
- $name = _pgettext('Collation', 'Hungarian');
- break;
- case 'icelandic':
- case 'is':
- $name = _pgettext('Collation', 'Icelandic');
- break;
- case 'japanese':
- case 'ja':
- $name = _pgettext('Collation', 'Japanese');
- break;
- case 'la':
- $name = _pgettext('Collation', 'Classical Latin');
- break;
- case 'latvian':
- case 'lv':
- $name = _pgettext('Collation', 'Latvian');
- break;
- case 'lithuanian':
- case 'lt':
- $name = _pgettext('Collation', 'Lithuanian');
- break;
- case 'korean':
- case 'ko':
- $name = _pgettext('Collation', 'Korean');
- break;
- case 'myanmar':
- case 'my':
- $name = _pgettext('Collation', 'Burmese');
- break;
- case 'persian':
- $name = _pgettext('Collation', 'Persian');
- break;
- case 'polish':
- case 'pl':
- $name = _pgettext('Collation', 'Polish');
- break;
- case 'roman':
- $name = _pgettext('Collation', 'West European');
- break;
- case 'romanian':
- case 'ro':
- $name = _pgettext('Collation', 'Romanian');
- break;
- case 'ru':
- $name = _pgettext('Collation', 'Russian');
- break;
- case 'si':
- case 'sinhala':
- $name = _pgettext('Collation', 'Sinhalese');
- break;
- case 'slovak':
- case 'sk':
- $name = _pgettext('Collation', 'Slovak');
- break;
- case 'slovenian':
- case 'sl':
- $name = _pgettext('Collation', 'Slovenian');
- break;
- case 'spanish':
- $name = _pgettext('Collation', 'Spanish (modern)');
- break;
- case 'es':
- /* Name is set later */
- $level = 3;
- break;
- case 'spanish2':
- $name = _pgettext('Collation', 'Spanish (traditional)');
- break;
- case 'swedish':
- case 'sv':
- $name = _pgettext('Collation', 'Swedish');
- break;
- case 'thai':
- case 'th':
- $name = _pgettext('Collation', 'Thai');
- break;
- case 'turkish':
- case 'tr':
- $name = _pgettext('Collation', 'Turkish');
- break;
- case 'ukrainian':
- case 'uk':
- $name = _pgettext('Collation', 'Ukrainian');
- break;
- case 'vietnamese':
- case 'vi':
- $name = _pgettext('Collation', 'Vietnamese');
- break;
- case 'unicode':
- if ($unknown) {
- $name = _pgettext('Collation', 'Unicode');
- }
- break;
- default:
- $found = false;
- }
- if ($found) {
- continue;
- }
- // Not parsed token, fall to next level
- }
- if ($level == 2) {
- /* Next will be variant */
- $level = 4;
- /* Germal variant */
- if ($part == 'pb') {
- $name = _pgettext('Collation', 'German (phone book order)');
- continue;
- }
- $name = _pgettext('Collation', 'German (dictionary order)');
- // Not parsed token, fall to next level
- }
- if ($level == 3) {
- /* Next will be variant */
- $level = 4;
- /* Spanish variant */
- if ($part == 'trad') {
- $name = _pgettext('Collation', 'Spanish (traditional)');
- continue;
- }
- $name = _pgettext('Collation', 'Spanish (modern)');
- // Not parsed token, fall to next level
- }
- if ($level == 4) {
- /* Next will be suffix */
- $level = 5;
- /* Variant */
- $found = true;
- switch ($part) {
- case '0900':
- $variant = 'UCA 9.0.0';
- break;
- case '520':
- $variant = 'UCA 5.2.0';
- break;
- case 'mysql561':
- $variant = 'MySQL 5.6.1';
- break;
- case 'mysql500':
- $variant = 'MySQL 5.0.0';
- break;
- default:
- $found = false;
- }
- if ($found) {
- continue;
- }
- // Not parsed token, fall to next level
- }
- if ($level == 5) {
- /* Suffixes */
- switch ($part) {
- case 'ci':
- $suffixes[] = _pgettext('Collation variant', 'case-insensitive');
- break;
- case 'cs':
- $suffixes[] = _pgettext('Collation variant', 'case-sensitive');
- break;
- case 'ai':
- $suffixes[] = _pgettext('Collation variant', 'accent-insensitive');
- break;
- case 'as':
- $suffixes[] = _pgettext('Collation variant', 'accent-sensitive');
- break;
- case 'ks':
- $suffixes[] = _pgettext('Collation variant', 'kana-sensitive');
- break;
- case 'w2':
- case 'l2':
- $suffixes[] = _pgettext('Collation variant', 'multi-level');
- break;
- case 'bin':
- $suffixes[] = _pgettext('Collation variant', 'binary');
- break;
- case 'nopad':
- $suffixes[] = _pgettext('Collation variant', 'no-pad');
- break;
- }
- }
- }
- $result = $name;
- if (! is_null($variant)) {
- $result .= ' (' . $variant . ')';
- }
- if (count($suffixes) > 0) {
- $result .= ', ' . implode(', ', $suffixes);
- }
- return $result;
- }
- }
|