Merge pull request #15348 from mauriciofauth/charset-collation-types
Add Charset and Collation value objects
This commit is contained in:
commit
54fa7ecaa3
@ -9,8 +9,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin;
|
||||
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Util;
|
||||
use PhpMyAdmin\Charsets\Charset;
|
||||
use PhpMyAdmin\Charsets\Collation;
|
||||
|
||||
/**
|
||||
* Class used to manage MySQL charsets
|
||||
@ -24,7 +24,7 @@ class Charsets
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $mysql_charset_map = [
|
||||
public static $mysqlCharsetMap = [
|
||||
'big5' => 'big5',
|
||||
'cp-866' => 'cp866',
|
||||
'euc-jp' => 'ujis',
|
||||
@ -50,20 +50,24 @@ class Charsets
|
||||
'windows-1257' => 'cp1257',
|
||||
];
|
||||
|
||||
private static $_charsets = [];
|
||||
|
||||
/**
|
||||
* The charset for the server
|
||||
*
|
||||
* @var string
|
||||
* @var Charset|null
|
||||
*/
|
||||
private static $_charset_server = null;
|
||||
private static $_charsets_descriptions = [];
|
||||
private static $_collations = [];
|
||||
private static $_default_collations = [];
|
||||
private static $serverCharset = null;
|
||||
|
||||
/**
|
||||
* Loads charset data from the MySQL server.
|
||||
* @var array<string, Charset>
|
||||
*/
|
||||
private static $charsets = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<string, Collation>>
|
||||
*/
|
||||
private static $collations = [];
|
||||
|
||||
/**
|
||||
* Loads charset data from the server
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
@ -73,7 +77,7 @@ class Charsets
|
||||
private static function loadCharsets(DatabaseInterface $dbi, bool $disableIs): void
|
||||
{
|
||||
/* Data already loaded */
|
||||
if (count(self::$_charsets) > 0) {
|
||||
if (count(self::$charsets) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -81,24 +85,24 @@ class Charsets
|
||||
$sql = 'SHOW CHARACTER SET';
|
||||
} else {
|
||||
$sql = 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `DESCRIPTION` AS `Description`'
|
||||
. ' `DEFAULT_COLLATE_NAME` AS `Default collation`,'
|
||||
. ' `DESCRIPTION` AS `Description`,'
|
||||
. ' `MAXLEN` AS `Maxlen`'
|
||||
. ' FROM `information_schema`.`CHARACTER_SETS`';
|
||||
}
|
||||
$res = $dbi->query($sql);
|
||||
|
||||
self::$_charsets = [];
|
||||
self::$charsets = [];
|
||||
while ($row = $dbi->fetchAssoc($res)) {
|
||||
$name = $row['Charset'];
|
||||
self::$_charsets[] = $name;
|
||||
self::$_charsets_descriptions[$name] = $row['Description'];
|
||||
self::$charsets[$row['Charset']] = Charset::fromServer($row);
|
||||
}
|
||||
$dbi->freeResult($res);
|
||||
|
||||
sort(self::$_charsets, SORT_STRING);
|
||||
ksort(self::$charsets, SORT_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads collation data from the MySQL server.
|
||||
* Loads collation data from the server
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
@ -108,105 +112,79 @@ class Charsets
|
||||
private static function loadCollations(DatabaseInterface $dbi, bool $disableIs): void
|
||||
{
|
||||
/* Data already loaded */
|
||||
if (count(self::$_collations) > 0) {
|
||||
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`'
|
||||
$sql = 'SELECT `COLLATION_NAME` AS `Collation`,'
|
||||
. ' `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `ID` AS `Id`,'
|
||||
. ' `IS_DEFAULT` AS `Default`,'
|
||||
. ' `IS_COMPILED` AS `Compiled`,'
|
||||
. ' `SORTLEN` AS `Sortlen`'
|
||||
. ' FROM `information_schema`.`COLLATIONS`';
|
||||
}
|
||||
|
||||
$res = $dbi->query($sql);
|
||||
|
||||
self::$collations = [];
|
||||
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;
|
||||
}
|
||||
self::$collations[$row['Charset']][$row['Collation']] = Collation::fromServer($row);
|
||||
}
|
||||
$dbi->freeResult($res);
|
||||
|
||||
foreach (self::$_collations as $key => $value) {
|
||||
sort(self::$_collations[$key], SORT_STRING);
|
||||
foreach (array_keys(self::$collations) as $charset) {
|
||||
ksort(self::$collations[$charset], SORT_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current MySQL server charset.
|
||||
* Get current server charset
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return string
|
||||
* @return Charset
|
||||
*/
|
||||
public static function getServerCharset(DatabaseInterface $dbi): string
|
||||
public static function getServerCharset(DatabaseInterface $dbi, bool $disableIs): Charset
|
||||
{
|
||||
if (self::$_charset_server !== null) {
|
||||
return self::$_charset_server;
|
||||
} else {
|
||||
self::$_charset_server = $dbi->getVariable('character_set_server');
|
||||
return self::$_charset_server;
|
||||
if (self::$serverCharset !== null) {
|
||||
return self::$serverCharset;
|
||||
}
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
$serverCharset = $dbi->getVariable('character_set_server');
|
||||
self::$serverCharset = self::$charsets[$serverCharset];
|
||||
return self::$serverCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL charsets
|
||||
* Get all server charsets
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCharsets(DatabaseInterface $dbi, bool $disableIs): array
|
||||
public static function getCharsets(DatabaseInterface $dbi, bool $disableIs): array
|
||||
{
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
return self::$_charsets;
|
||||
return self::$charsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MySQL charsets descriptions
|
||||
* Get all server collations
|
||||
*
|
||||
* @param DatabaseInterface $dbi DatabaseInterface instance
|
||||
* @param boolean $disableIs Disable use of INFORMATION_SCHEMA
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMySQLCharsetsDescriptions(DatabaseInterface $dbi, bool $disableIs): array
|
||||
{
|
||||
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, bool $disableIs): array
|
||||
public static function getCollations(DatabaseInterface $dbi, bool $disableIs): array
|
||||
{
|
||||
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, bool $disableIs): array
|
||||
{
|
||||
self::loadCollations($dbi, $disableIs);
|
||||
return self::$_default_collations;
|
||||
return self::$collations;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,34 +210,25 @@ class Charsets
|
||||
bool $submitOnChange = false
|
||||
): string {
|
||||
self::loadCharsets($dbi, $disableIs);
|
||||
if (empty($name)) {
|
||||
$name = 'character_set';
|
||||
|
||||
$charsets = [];
|
||||
/** @var Charset $charset */
|
||||
foreach (self::$charsets as $charset) {
|
||||
$charsets[] = [
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'is_selected' => $default === $charset->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
$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;
|
||||
$template = new Template();
|
||||
return $template->render('charset_select', [
|
||||
'name' => $name,
|
||||
'id' => $id,
|
||||
'submit_on_change' => $submitOnChange,
|
||||
'has_label' => $label,
|
||||
'charsets' => $charsets,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,40 +255,34 @@ class Charsets
|
||||
): string {
|
||||
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";
|
||||
$charsets = [];
|
||||
/** @var Charset $charset */
|
||||
foreach (self::$charsets as $charset) {
|
||||
$collations = [];
|
||||
/** @var Collation $collation */
|
||||
foreach (self::$collations[$charset->getName()] as $collation) {
|
||||
$collations[] = [
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
'is_selected' => $default === $collation->getName(),
|
||||
];
|
||||
}
|
||||
$return_str .= '</optgroup>' . "\n";
|
||||
$charsets[] = [
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'collations' => $collations,
|
||||
];
|
||||
}
|
||||
$return_str .= '</select>' . "\n";
|
||||
|
||||
return $return_str;
|
||||
$template = new Template();
|
||||
return $template->render('collation_select', [
|
||||
'name' => $name,
|
||||
'id' => $id,
|
||||
'submit_on_change' => $submitOnChange,
|
||||
'has_label' => $label,
|
||||
'charsets' => $charsets,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
103
libraries/classes/Charsets/Charset.php
Normal file
103
libraries/classes/Charsets/Charset.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Value object class for a character set
|
||||
* @package PhpMyAdmin\Charsets
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Charsets;
|
||||
|
||||
/**
|
||||
* Value object class for a character set
|
||||
* @package PhpMyAdmin\Charsets
|
||||
*/
|
||||
final class Charset
|
||||
{
|
||||
/**
|
||||
* The character set name
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* A description of the character set
|
||||
* @var string
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* The default collation for the character set
|
||||
* @var string
|
||||
*/
|
||||
private $defaultCollation;
|
||||
|
||||
/**
|
||||
* The maximum number of bytes required to store one character
|
||||
* @var int
|
||||
*/
|
||||
private $maxLength;
|
||||
|
||||
/**
|
||||
* @param string $name Charset name
|
||||
* @param string $description Description
|
||||
* @param string $defaultCollation Default collation
|
||||
* @param int $maxLength Maximum length
|
||||
*/
|
||||
private function __construct(
|
||||
string $name,
|
||||
string $description,
|
||||
string $defaultCollation,
|
||||
int $maxLength
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->description = $description;
|
||||
$this->defaultCollation = $defaultCollation;
|
||||
$this->maxLength = $maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $state State obtained from the database server
|
||||
* @return Charset
|
||||
*/
|
||||
public static function fromServer(array $state): self
|
||||
{
|
||||
return new self(
|
||||
$state['Charset'] ?? '',
|
||||
$state['Description'] ?? '',
|
||||
$state['Default collation'] ?? '',
|
||||
(int) $state['Maxlen'] ?? 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultCollation(): string
|
||||
{
|
||||
return $this->defaultCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxLength(): int
|
||||
{
|
||||
return $this->maxLength;
|
||||
}
|
||||
}
|
||||
174
libraries/classes/Charsets/Collation.php
Normal file
174
libraries/classes/Charsets/Collation.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* Value object class for a collation
|
||||
* @package PhpMyAdmin\Charsets
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace PhpMyAdmin\Charsets;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
|
||||
/**
|
||||
* Value object class for a collation
|
||||
* @package PhpMyAdmin\Charsets
|
||||
*/
|
||||
final class Collation
|
||||
{
|
||||
/**
|
||||
* The collation name
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* A description of the collation
|
||||
* @var string
|
||||
*/
|
||||
private $description;
|
||||
|
||||
/**
|
||||
* The name of the character set with which the collation is associated
|
||||
* @var string
|
||||
*/
|
||||
private $charset;
|
||||
|
||||
/**
|
||||
* The collation ID
|
||||
* @var int
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Whether the collation is the default for its character set
|
||||
* @var bool
|
||||
*/
|
||||
private $isDefault;
|
||||
|
||||
/**
|
||||
* Whether the character set is compiled into the server
|
||||
* @var bool
|
||||
*/
|
||||
private $isCompiled;
|
||||
|
||||
/**
|
||||
* Used for determining the memory used to sort strings in this collation
|
||||
* @var int
|
||||
*/
|
||||
private $sortLength;
|
||||
|
||||
/**
|
||||
* The collation pad attribute
|
||||
* @var string
|
||||
*/
|
||||
private $padAttribute;
|
||||
|
||||
/**
|
||||
* @param string $name Collation name
|
||||
* @param string $charset Related charset
|
||||
* @param int $id Collation ID
|
||||
* @param bool $isDefault Whether is the default
|
||||
* @param bool $isCompiled Whether the charset is compiled
|
||||
* @param int $sortLength Sort length
|
||||
* @param string $padAttribute Pad attribute
|
||||
*/
|
||||
private function __construct(
|
||||
string $name,
|
||||
string $charset,
|
||||
int $id,
|
||||
bool $isDefault,
|
||||
bool $isCompiled,
|
||||
int $sortLength,
|
||||
string $padAttribute
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->charset = $charset;
|
||||
$this->id = $id;
|
||||
$this->isDefault = $isDefault;
|
||||
$this->isCompiled = $isCompiled;
|
||||
$this->sortLength = $sortLength;
|
||||
$this->padAttribute = $padAttribute;
|
||||
$this->description = Charsets::getCollationDescr($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $state State obtained from the database server
|
||||
* @return self
|
||||
*/
|
||||
public static function fromServer(array $state): self
|
||||
{
|
||||
return new self(
|
||||
$state['Collation'] ?? '',
|
||||
$state['Charset'] ?? '',
|
||||
(int) $state['Id'] ?? 0,
|
||||
isset($state['Default']) && ($state['Default'] === 'Yes' || $state['Default'] === '1'),
|
||||
isset($state['Compiled']) && ($state['Compiled'] === 'Yes' || $state['Compiled'] === '1'),
|
||||
(int) $state['Sortlen'] ?? 0,
|
||||
$state['Pad_attribute'] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCharset(): string
|
||||
{
|
||||
return $this->charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDefault(): bool
|
||||
{
|
||||
return $this->isDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompiled(): bool
|
||||
{
|
||||
return $this->isCompiled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSortLength(): int
|
||||
{
|
||||
return $this->sortLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPadAttribute(): string
|
||||
{
|
||||
return $this->padAttribute;
|
||||
}
|
||||
}
|
||||
@ -167,12 +167,7 @@ class HomeController extends AbstractController
|
||||
$hostInfo .= ')';
|
||||
}
|
||||
|
||||
$unicode = Charsets::$mysql_charset_map['utf-8'];
|
||||
$charsets = Charsets::getMySQLCharsetsDescriptions(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
|
||||
$serverCharset = Charsets::getServerCharset($this->dbi, $cfg['Server']['DisableIS']);
|
||||
$databaseServer = [
|
||||
'host' => $hostInfo,
|
||||
'type' => Util::getServerType(),
|
||||
@ -180,7 +175,7 @@ class HomeController extends AbstractController
|
||||
'version' => $this->dbi->getVersionString() . ' - ' . $this->dbi->getVersionComment(),
|
||||
'protocol' => $this->dbi->getProtoInfo(),
|
||||
'user' => $this->dbi->fetchValue('SELECT USER();'),
|
||||
'charset' => $charsets[$unicode] . ' (' . $unicode . ')',
|
||||
'charset' => $serverCharset->getDescription() . ' (' . $serverCharset->getName() . ')',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ declare(strict_types=1);
|
||||
namespace PhpMyAdmin\Controllers\Server;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Charsets\Charset;
|
||||
use PhpMyAdmin\Charsets\Collation;
|
||||
use PhpMyAdmin\Controllers\AbstractController;
|
||||
use PhpMyAdmin\DatabaseInterface;
|
||||
use PhpMyAdmin\Response;
|
||||
@ -27,58 +29,36 @@ class CollationsController extends AbstractController
|
||||
*/
|
||||
private $charsets;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $charsetsDescriptions;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $collations;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $defaultCollations;
|
||||
|
||||
/**
|
||||
* CollationsController constructor.
|
||||
*
|
||||
* @param Response $response Response object
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param Template $template Template object
|
||||
* @param array|null $charsets Array of charsets
|
||||
* @param array|null $charsetsDescriptions Array of charsets descriptions
|
||||
* @param array|null $collations Array of collations
|
||||
* @param array|null $defaultCollations Array of default collations
|
||||
* @param Response $response Response object
|
||||
* @param DatabaseInterface $dbi DatabaseInterface object
|
||||
* @param Template $template Template object
|
||||
* @param array|null $charsets Array of charsets
|
||||
* @param array|null $collations Array of collations
|
||||
*/
|
||||
public function __construct(
|
||||
$response,
|
||||
$dbi,
|
||||
Template $template,
|
||||
?array $charsets = null,
|
||||
?array $charsetsDescriptions = null,
|
||||
?array $collations = null,
|
||||
?array $defaultCollations = null
|
||||
?array $collations = null
|
||||
) {
|
||||
global $cfg;
|
||||
|
||||
parent::__construct($response, $dbi, $template);
|
||||
|
||||
$this->charsets = $charsets ?? Charsets::getMySQLCharsets(
|
||||
$this->charsets = $charsets ?? Charsets::getCharsets(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
$this->charsetsDescriptions = $charsetsDescriptions ?? Charsets::getMySQLCharsetsDescriptions(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
$this->collations = $collations ?? Charsets::getMySQLCollations(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
$this->defaultCollations = $defaultCollations ?? Charsets::getMySQLCollationsDefault(
|
||||
$this->collations = $collations ?? Charsets::getCollations(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
@ -94,19 +74,21 @@ class CollationsController extends AbstractController
|
||||
include_once ROOT_PATH . 'libraries/server_common.inc.php';
|
||||
|
||||
$charsets = [];
|
||||
/** @var Charset $charset */
|
||||
foreach ($this->charsets as $charset) {
|
||||
$charsetCollations = [];
|
||||
foreach ($this->collations[$charset] as $collation) {
|
||||
/** @var Collation $collation */
|
||||
foreach ($this->collations[$charset->getName()] as $collation) {
|
||||
$charsetCollations[] = [
|
||||
'name' => $collation,
|
||||
'description' => Charsets::getCollationDescr($collation),
|
||||
'is_default' => $collation === $this->defaultCollations[$charset],
|
||||
'name' => $collation->getName(),
|
||||
'description' => $collation->getDescription(),
|
||||
'is_default' => $collation->isDefault(),
|
||||
];
|
||||
}
|
||||
|
||||
$charsets[] = [
|
||||
'name' => $charset,
|
||||
'description' => $this->charsetsDescriptions[$charset] ?? '',
|
||||
'name' => $charset->getName(),
|
||||
'description' => $charset->getDescription(),
|
||||
'collations' => $charsetCollations,
|
||||
];
|
||||
}
|
||||
|
||||
@ -157,16 +157,16 @@ class DatabasesController extends AbstractController
|
||||
$sqlQuery = 'CREATE DATABASE ' . Util::backquote($params['new_db']);
|
||||
if (! empty($params['db_collation'])) {
|
||||
list($databaseCharset) = explode('_', $params['db_collation']);
|
||||
$charsets = Charsets::getMySQLCharsets(
|
||||
$charsets = Charsets::getCharsets(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
$collations = Charsets::getMySQLCollations(
|
||||
$collations = Charsets::getCollations(
|
||||
$this->dbi,
|
||||
$cfg['Server']['DisableIS']
|
||||
);
|
||||
if (in_array($databaseCharset, $charsets)
|
||||
&& in_array($params['db_collation'], $collations[$databaseCharset])
|
||||
if (in_array($databaseCharset, array_keys($charsets))
|
||||
&& in_array($params['db_collation'], array_keys($collations[$databaseCharset]))
|
||||
) {
|
||||
$sqlQuery .= ' DEFAULT'
|
||||
. Util::getCharsetQueryPart($params['db_collation']);
|
||||
|
||||
@ -781,47 +781,71 @@ class DbiDummy implements DbiExtension
|
||||
],
|
||||
[
|
||||
'query' => 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `DESCRIPTION` AS `Description`'
|
||||
. ' `DEFAULT_COLLATE_NAME` AS `Default collation`,'
|
||||
. ' `DESCRIPTION` AS `Description`,'
|
||||
. ' `MAXLEN` AS `Maxlen`'
|
||||
. ' FROM `information_schema`.`CHARACTER_SETS`',
|
||||
'columns' => [
|
||||
'Charset',
|
||||
'Default collation',
|
||||
'Description',
|
||||
],
|
||||
'result' => [
|
||||
[
|
||||
'utf8',
|
||||
'UTF-8 Unicode',
|
||||
],
|
||||
[
|
||||
'latin1',
|
||||
'cp1252 West European',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'query' => 'SELECT `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `COLLATION_NAME` AS `Collation`, `IS_DEFAULT` AS `Default`'
|
||||
. ' FROM `information_schema`.`COLLATIONS`',
|
||||
'columns' => [
|
||||
'Charset',
|
||||
'Collation',
|
||||
'Default',
|
||||
'Maxlen',
|
||||
],
|
||||
'result' => [
|
||||
[
|
||||
'utf8',
|
||||
'utf8_general_ci',
|
||||
'Yes',
|
||||
],
|
||||
[
|
||||
'utf8',
|
||||
'utf8_bin',
|
||||
'',
|
||||
'UTF-8 Unicode',
|
||||
'3',
|
||||
],
|
||||
[
|
||||
'latin1',
|
||||
'latin1_swedish_ci',
|
||||
'cp1252 West European',
|
||||
'1',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'query' => 'SELECT `COLLATION_NAME` AS `Collation`,'
|
||||
. ' `CHARACTER_SET_NAME` AS `Charset`,'
|
||||
. ' `ID` AS `Id`,'
|
||||
. ' `IS_DEFAULT` AS `Default`,'
|
||||
. ' `IS_COMPILED` AS `Compiled`,'
|
||||
. ' `SORTLEN` AS `Sortlen`'
|
||||
. ' FROM `information_schema`.`COLLATIONS`',
|
||||
'columns' => [
|
||||
'Collation',
|
||||
'Charset',
|
||||
'Id',
|
||||
'Default',
|
||||
'Compiled',
|
||||
'Sortlen',
|
||||
],
|
||||
'result' => [
|
||||
[
|
||||
'utf8_general_ci',
|
||||
'utf8',
|
||||
'33',
|
||||
'Yes',
|
||||
'Yes',
|
||||
'1',
|
||||
],
|
||||
[
|
||||
'utf8_bin',
|
||||
'utf8',
|
||||
'83',
|
||||
'',
|
||||
'Yes',
|
||||
'1',
|
||||
],
|
||||
[
|
||||
'latin1_swedish_ci',
|
||||
'latin1',
|
||||
'8',
|
||||
'Yes',
|
||||
'Yes',
|
||||
'1',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
@ -775,13 +775,13 @@ class ExportSql extends ExportPlugin
|
||||
// so that a utility like the mysql client can interpret
|
||||
// the file correctly
|
||||
if (isset($GLOBALS['charset'])
|
||||
&& isset(Charsets::$mysql_charset_map[$GLOBALS['charset']])
|
||||
&& isset(Charsets::$mysqlCharsetMap[$GLOBALS['charset']])
|
||||
) {
|
||||
// we got a charset from the export dialog
|
||||
$set_names = Charsets::$mysql_charset_map[$GLOBALS['charset']];
|
||||
$set_names = Charsets::$mysqlCharsetMap[$GLOBALS['charset']];
|
||||
} else {
|
||||
// by default we use the connection charset
|
||||
$set_names = Charsets::$mysql_charset_map['utf-8'];
|
||||
$set_names = Charsets::$mysqlCharsetMap['utf-8'];
|
||||
}
|
||||
if ($set_names == 'utf8' && $GLOBALS['dbi']->getVersion() > 50503) {
|
||||
$set_names = 'utf8mb4';
|
||||
|
||||
13
templates/charset_select.twig
Normal file
13
templates/charset_select.twig
Normal file
@ -0,0 +1,13 @@
|
||||
<select lang="en" dir="ltr" name="{{ name|default('character_set') }}"
|
||||
{%- if id is not empty %} id="{{ id }}"{% endif -%}
|
||||
{%- if submit_on_change %} class="autosubmit"{% endif %}>
|
||||
{% if has_label %}
|
||||
<option value="">{% trans 'Charset' %}</option>
|
||||
{% endif %}
|
||||
<option value=""></option>
|
||||
{% for charset in charsets %}
|
||||
<option value="{{ charset.name }}" title="{{ charset.description }}"{{ charset.is_selected ? ' selected' }}>
|
||||
{{- charset.name -}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
17
templates/collation_select.twig
Normal file
17
templates/collation_select.twig
Normal file
@ -0,0 +1,17 @@
|
||||
<select lang="en" dir="ltr" name="{{ name|default('collation') }}"
|
||||
{%- if id is not empty %} id="{{ id }}"{% endif -%}
|
||||
{%- if submit_on_change %} class="autosubmit"{% endif %}>
|
||||
{% if has_label %}
|
||||
<option value="">{% trans 'Collation' %}</option>
|
||||
{% endif %}
|
||||
<option value=""></option>
|
||||
{% for charset in charsets %}
|
||||
<optgroup label="{{ charset.name }}" title="{{ charset.description }}">
|
||||
{% for collation in charset.collations %}
|
||||
<option value="{{ collation.name }}" title="{{ collation.description }}"{{ collation.is_selected ? ' selected' }}>
|
||||
{{- collation.name -}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</optgroup>
|
||||
{% endfor %}
|
||||
</select>
|
||||
@ -459,6 +459,6 @@ class CharsetsTest extends TestCase
|
||||
$this->assertStringNotContainsString('Charset</option>', $result);
|
||||
$this->assertStringContainsString('class="autosubmit"', $result);
|
||||
$this->assertStringContainsString('id="test_id"', $result);
|
||||
$this->assertStringContainsString('selected="selected">latin1', $result);
|
||||
$this->assertStringContainsString('selected>latin1', $result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,39 +45,10 @@ class CollationsControllerTest extends TestCase
|
||||
*/
|
||||
public function testIndexAction(): void
|
||||
{
|
||||
$charsets = [
|
||||
'armscii8',
|
||||
'ascii',
|
||||
'big5',
|
||||
'binary',
|
||||
];
|
||||
$charsetsDescriptions = [
|
||||
'armscii8' => 'PMA_armscii8_general_ci',
|
||||
'ascii' => 'PMA_ascii_general_ci',
|
||||
'big5' => 'PMA_big5_general_ci',
|
||||
'binary' => 'PMA_binary_general_ci',
|
||||
];
|
||||
$collations = [
|
||||
'armscii8' => ['armscii8'],
|
||||
'ascii' => ['ascii'],
|
||||
'big5' => ['big5'],
|
||||
'binary' => ['binary'],
|
||||
];
|
||||
$defaultCollations = [
|
||||
'armscii8' => 'armscii8',
|
||||
'ascii' => 'ascii',
|
||||
'big5' => 'big5',
|
||||
'binary' => 'binary',
|
||||
];
|
||||
|
||||
$controller = new CollationsController(
|
||||
Response::getInstance(),
|
||||
$GLOBALS['dbi'],
|
||||
new Template(),
|
||||
$charsets,
|
||||
$charsetsDescriptions,
|
||||
$collations,
|
||||
$defaultCollations
|
||||
new Template()
|
||||
);
|
||||
|
||||
$actual = $controller->indexAction();
|
||||
@ -95,31 +66,27 @@ class CollationsControllerTest extends TestCase
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<em>PMA_armscii8_general_ci</em>',
|
||||
'<em>UTF-8 Unicode</em>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<td>armscii8</td>',
|
||||
'<td>utf8_general_ci</td>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<td>' . Charsets::getCollationDescr('armscii8') . '</td>',
|
||||
'<td>' . Charsets::getCollationDescr('utf8_general_ci') . '</td>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<em>PMA_ascii_general_ci</em>',
|
||||
'<em>cp1252 West European</em>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<td>ascii</td>',
|
||||
'<td>latin1_swedish_ci</td>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<em>PMA_big5_general_ci</em>',
|
||||
$actual
|
||||
);
|
||||
$this->assertStringContainsString(
|
||||
'<td>big5</td>',
|
||||
'<td>Swedish, case-insensitive</td>',
|
||||
$actual
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user