Phpmyadmin кодирует фатальную ошибку «Неопределенный индекс: utf8mb3»

#phpmyadmin

Вопрос:

Я установил новый экземпляр phpMyAdmin для работы с MySQL8. При входе на главную страницу я получаю предупреждение с сообщением:

 Notice in ./libraries/classes/Charsets.php#154
 Undefined index: utf8mb3

Backtrace

./libraries/classes/Controllers/HomeController.php#163: PhpMyAdminCharsets::getServerCharset(,
boolean false,)
./libraries/classes/Routing.php#186: PhpMyAdminControllersHomeController->index(array)
./index.php#18: PhpMyAdminRouting::callControllerForRoute(
string '/',,,)
 

Моя кодировка сервера и клиента MySQL: utf8.
Есть идеи, как я могу это исправить?

Ответ №1:

Причина

По-видимому, это вызвано ошибкой в MySQL 8 при установке character_set_server значения utf8 в конфигурации MySQL ( [mysqld] ).

В руководстве по MySQL говорится:

MySQL немедленно преобразует экземпляры utf8mb3 в операторах в utf8, поэтому в таких операторах, как SHOW CREATE TABLE или SELECT CHARACTER_SET_NAME ИЗ INFORMATION_SCHEMA.COLUMNS или SELECT COLLATION_NAME ИЗ INFORMATION_SCHEMA.COLUMNS, пользователи видят имя utf8 или utf8_collation_substring.

Однако запрос SHOW VARIABLES LIKE 'character_set_server'; все равно возвращает

 ---------------------- ---------- 
| Variable_name        | Value   |
 ---------------------- --------- 
| character_set_server | utf8mb3 |
 ---------------------- --------- 
 

-> utf8mb3

Соответствующую часть кода в phpMyAdmin можно найти в libraries/classes/Charsets.php :

   /**
  * Get current server charset
  *
  * @param DatabaseInterface $dbi       DatabaseInterface instance
  * @param bool              $disableIs Disable use of INFORMATION_SCHEMA
  */
public static function getServerCharset(DatabaseInterface $dbi, bool $disableIs): Charset
{
    if (self::$serverCharset !== null) {
        return self::$serverCharset;
    }
    self::loadCharsets($dbi, $disableIs);
    $serverCharset = $dbi->getVariable('character_set_server');
    if (! is_string($serverCharset)) {// MySQL 5.7.8 fallback, issue #15614
        $serverCharset = $dbi->fetchValue('SELECT @@character_set_server;');
    }
    self::$serverCharset = self::$charsets[$serverCharset];
    return self::$serverCharset;
}
 

То, что phpMyAdmin делает в методе getServerCharset в libraries/classes/Charsets.php (который вызывает ошибку), заключается в следующем:

  • Он проверяет, определил ли он уже кодировку. Если нет,
  • он загружает массив кодировок, доступных с сервера MySQL с помощью этого метода loadCharsets . Однако это делается либо с помощью запроса SHOW CHARACTER SET; , либо с помощью запроса information_schema . В обоих случаях utf8 возвращается (вместо utf8mb3 ), как описано выше в руководстве MySQL.
  • Затем он получает кодировку сервера с запросом SHOW VARIABLES LIKE 'character_set_server'; (здесь utf8mb3 возвращается как результат, как показано выше).
  • Существует запасной вариант (не относящийся к нашему случаю) из-за ошибки в MySQL 5.7.8, которую мы можем игнорировать.
  • Он записывает результат в переменную self::$serverCharset , получая элемент массива с ключом $serverCharset (который есть utf8mb3 ) из массива всех доступных кодировок сервера . Как мы знаем, utf8mb3 в массиве доступных кодировок сервера нет ключа (только utf8 для которого используется псевдоним utf8mb3 ). Следовательно, возникает ошибка.

Как это исправить

Чтобы исправить это, либо MySQL должен вместо этого вернуться utf8 к запросу SHOW VARIABLES LIKE 'character_set_server'; , на который мы не можем легко повлиять (возможно, потребуется создать отчет об ошибке), либо нам придется обойти это в исходном коде phpMyAdmin.

Для этого я добавил

 if ($serverCharset === "utf8mb3") {
    $serverCharset = "utf8";
}
 

перед строкой

 self::$serverCharset = self::$charsets[$serverCharset];
 

так что теперь это выглядит так:

   /**
  * Get current server charset
  *
  * @param DatabaseInterface $dbi       DatabaseInterface instance
  * @param bool              $disableIs Disable use of INFORMATION_SCHEMA
  */
public static function getServerCharset(DatabaseInterface $dbi, bool $disableIs): Charset
{
    if (self::$serverCharset !== null) {
        return self::$serverCharset;
    }
    self::loadCharsets($dbi, $disableIs);
    $serverCharset = $dbi->getVariable('character_set_server');
    if (! is_string($serverCharset)) {// MySQL 5.7.8 fallback, issue #15614
        $serverCharset = $dbi->fetchValue('SELECT @@character_set_server;');
    }

    if ($serverCharset === "utf8mb3") {
        $serverCharset = "utf8";
    }

    self::$serverCharset = self::$charsets[$serverCharset];
    return self::$serverCharset;
}
 

Ошибка больше не должна возникать.

Комментарии:

1. Спасибо! Это исправило фатальную ошибку. Планируете ли вы включить это исправление в будущий выпуск?

Ответ №2:

Мы ищем вас, пожалуйста, в будущем сообщайте об этих проблемах на наш трекер GitHub

См.: выпуск №16931

Вот официальное исправление: a2855079abccc05940286424d3017bf8ca9b3c7d

Решение: установите phpMyAdmin 5.1.1 или новее