MySQL utf8mb4, Ошибки при сохранении Emojis
Я пытаюсь сохранить имена пользователей из службы в моей базе данных MySQL. Эти имена могут содержать смайлики, такие как 🙈😂😱🍰 (только для примера)
После небольшого поиска я обнаружил, что этот стекопоток связан с этим руководством. Я следовал за шагами, и похоже, что все настроено правильно.
У меня есть база данных (набор символов и сопоставление, равные utf8mb4 (_unicode_ci)), таблица с именем TestTable, также настроенная таким образом, а также столбец "Текст", настроенный таким образом (VARCHAR (191) utf8mb4_unicode_ci).
Когда я пытаюсь сохранить эмодзи, я получаю сообщение об ошибке:
Example of error for shortcake (🍰):
Warning: #1300 Invalid utf8 character string: 'F09F8D'
Warning: #1366 Incorrect string value: '\xF0\x9F\x8D\xB0' for column 'Text' at row 1
Единственное эмодзи, которое мне удалось спасти, это солнце was
Хотя я не пытался все из них, чтобы быть честным.
Что-то мне не хватает в конфигурации?
Обратите внимание: все тесты сохранения не были связаны с клиентской стороной. Я использую phpmyadmin, чтобы вручную изменить значения и сохранить данные. Поэтому о правильной конфигурации клиентской части я буду заботиться после того, как сервер должным образом сохранит эмодзи.
Еще одно замечание: в настоящее время при сохранении смайликов я либо получаю ошибку, как указано выше, либо не получаю ошибку, и данные имени Username 🍰
будут сохранены как Username????
, Ошибка или нет ошибки зависит от того, как я сохраняю. При создании/сохранении с помощью оператора SQL я сохраняю с вопросительными знаками, при редактировании inline я сохраняю с вопросительными знаками, при редактировании с помощью кнопки редактирования я получаю ошибку.
благодарю вас
РЕДАКТИРОВАТЬ 1: Хорошо, так что я думаю, что я обнаружил проблему, но не решение. Похоже, что конкретные переменные базы данных не изменились должным образом.
Когда я вошел в систему как root на моем сервере и считал переменные (глобальные):
Используемый запрос: SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
Для моей базы данных (в phpmyadmin, тот же запрос) это выглядит следующим образом:
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
Как я могу настроить эти параметры для конкретной базы данных? Также, хотя у меня есть первые показанные настройки по умолчанию, при создании новой базы данных я получаю вторую как настройки.
Изменить 2:
Вот мой файл my.cnf
:
[client]
port=3306
socket=/var/run/mysqld/mysqld.sock
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld_safe]
socket=/var/run/mysqld/mysqld.sock
[mysqld]
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
socket=/var/run/mysqld/mysqld.sock
port=3306
basedir=/usr
datadir=/var/lib/mysql
tmpdir=/tmp
lc-messages-dir=/usr/share/mysql
log_error=/var/log/mysql/error.log
max_connections=200
max_user_connections=30
wait_timeout=30
interactive_timeout=50
long_query_time=5
innodb_file_per_table
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
!includedir /etc/mysql/conf.d/
Ответы
Ответ 1
character_set_client
, _connection
и _results
должны быть utf8mb4
для того, чтобы этот пирог был съедобным.
Что-то, где-то, устанавливает подмножество этих элементов отдельно. Rummage через my.cnf и phpmyadmin настройки - что-то не устанавливает все три.
Если выполняется SET NAMES utf8mb4
, все три установлены правильно.
Солнце сияет, потому что оно всего 3 байта - E2 98 80
; utf8 достаточно для 3-байтовых кодировок utf8 символов Unicode.
Ответ 2
Вполне вероятно, что ваша служба/приложение соединяется с "utf8" вместо "utf8mb4" для набора символов клиента. Это до клиентского приложения.
Для приложения PHP см. Http://php.net/manual/en/function.mysql-set-charset.php или http://php.net/manual/en/mysqli.set-charset.php.
Для приложения Python см. Https://github.com/PyMySQL/PyMySQL#example или http://docs.sqlalchemy.org/en/latest/dialects/mysql.html#mysql-unicode.
Также убедитесь, что ваши столбцы действительно utf8mb4. Один прямой путь таков:
mysql> SELECT character_set_name FROM information_schema.'COLUMNS' WHERE table_name = "user" AND column_name = "displayname";
+--------------------+
| character_set_name |
+--------------------+
| utf8mb4 |
+--------------------+
1 row in set (0.00 sec)
Ответ 3
Для меня оказалось, что проблема связана с клиентом mysql.
Обновления клиента mysql my.cnf
char на сервере и привели к непреднамеренной настройке символов.
Итак, мне нужно было просто добавить character-set-client-handshake = FALSE
.
Это отключает настройку клиента из-за нарушения настройки char.
my.cnf
будет таким.
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
...
Надеюсь, что это поможет.
Ответ 4
ALTER TABLE table_name
CHANGE column_name
column_name
VARCHAR (255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, NULL DEFAULT;
пример запроса:
ALTER TABLE 'reactions' CHANGE 'emoji' 'emoji' VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL;
![enter image description here]()
После этого удачно в состоянии хранить смайлики в таблице:
![enter image description here]()
Ответ 5
Я не горжусь этим ответом, потому что он использует грубую силу для очистки ввода. Это жестоко, но это работает
function cleanWord($string, $debug = false) {
$new_string = "";
for ($i=0;$i<strlen($string);$i++) {
$letter = substr($string, $i, 1);
if ($debug) {
echo "Letter: " . $letter . "<BR>";
echo "Code: " . ord($letter) . "<BR><BR>";
}
$blnSkip = false;
if (ord($letter)=="146") {
$letter = "´";
$blnSkip = true;
}
if (ord($letter)=="233") {
$letter = "é";
$blnSkip = true;
}
if (ord($letter)=="147" || ord($letter)=="148") {
$letter = """;
$blnSkip = true;
}
if (ord($letter)=="151") {
$letter = "–";
$blnSkip = true;
}
if ($blnSkip) {
$new_string .= $letter;
break;
}
if (ord($letter) > 127) {
$letter = "�" . ord($letter) . ";";
}
$new_string .= $letter;
}
if ($new_string!="") {
$string = $new_string;
}
//optional
$string = str_replace("\r\n", "<BR>", $string);
return $string;
}
//clean up the input
$message = cleanWord($message);
//now you can insert it as part of SQL statement
$sql = "INSERT INTO tbl_message ('message')
VALUES ('" . addslashes($message) . "')";