Я работаю с базой данных, которая использует кодировку UTF8 и имеет много имен пользователей, которые содержат специальные символы, такие как «▫ ▫ Sony»
При запросе пользовательской таблицы Lumen отвечает неверными данными. Я пытался запросить ту же таблицу с помощью mysqli
а также PDO
и я получаю ожидаемые результаты. Я установил примерный маршрут для его проверки:
$app->get("charset", function() {
$mysqli = new mysqli("localhost", "user", "password", "database");
$res = $mysqli->query("select name from users where id = 1");
$dbh = new PDO('mysql:host=localhost;dbname=database', "user", "password");
$stmt = $dbh->query("select name from users where id = 1");
$lumen = DB::select("select name from users where id = 1");
return response()->json([
"mysqli" => $res->fetch_assoc(),
"pdo" => $stmt->fetchAll(PDO::FETCH_ASSOC),
"framework" => $lumen
]);
});
При доступе к маршруту я получаю следующий ответ:
{
"mysqli": {
"name": "Ғђ ▫ Sony"},
"pdo": [
{
"name": "Ғђ ▫ Sony"}
],
"framework": [
{
"name": "Ò’Ñ’ â–« Sony"}
]
}
Вот скриншот ответа в случае, если текст выше не отображается правильно:
Насколько я могу судить, конфигурация Lumen для MySQL по умолчанию установлена в UTF8 и неизменна — я обнаружил следующее в vendor/laravel/lumen-framework/config/database
:
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => env('DB_PREFIX', ''),
'timezone' => env('DB_TIMEZONE','+00:00'),
'strict' => false,
],
Я в недоумении относительно того, что может быть причиной этого. Что еще я могу сделать, чтобы попытаться отследить это несоответствие?
Этот ответ основан на моих предыдущих комментариях выше.
Кодировка соединения MySQL определяет, какая кодировка используется для связи между клиентом MySQL (PHP) и сервером. Неважно, какая кодировка используется в качестве внутренней кодировки в реальных таблицах MySQL. Сервер MySQL автоматически преобразует данные между кодировкой таблицы и кодировкой соединения. Таким образом, кодировка соединения в основном определяет формат, в котором вы ожидаете получить данные из MySQL, а также в каком формате вы вставляете данные в MySQL.
Вы уверены, что данные правильно закодированы в utf8 в базе данных?
Похоже, вы используете UTF8 только для соединения с БД lumen (если это значение по умолчанию), но вы не используете UTF8 с примерами соединений mysqli или PDO. Получаете ли вы тот же результат, если установить mysqli charset с помощью $mysqli->set_charset("utf8");
и кодировка PDO с использованием new PDO('mysql:host=localhost;dbname=database;charset=utf8', "user", "password");
?
Исходя из вашего кода и примера вывода, может показаться, что вы правильно получаете данные в UTF8 из соединения с БД lumen, но вывод не отображается как UTF8.
Это также объясняет, почему выходные данные mysqli и PDO отображаются правильно, потому что они не возвращают данные в UTF8 (потому что вы не установили их кодировку соединения в UTF8), но по умолчанию они, кажется, совпадают с любой кодировкой, в которой вы выводите выходные данные. в (видимо «latin1» или совместимый).
Если вы просматриваете выходные данные в веб-браузере, убедитесь, что кодировка выходной страницы определена правильно (например, с помощью заголовка).
Редактировать:
Между прочим, не должно иметь значения, какая кодировка соединения используется в другой системе, которая вставляет данные, если кодировка соединения совпадает с кодировкой данных, которые передаются через соединение.
Установка кодировки соединения на latin1 означает, что вы получите строковые данные как latin1, когда будете делать SELECT. Так что, похоже, ваш вывод обрабатывается как latin1 вместо UTF-8. Вероятно, было бы лучше, если бы вы исправили вывод скрипта, чтобы он правильно отображал «как UTF-8», если ваша среда вывода (например, веб-браузер) поддерживает это. Потому что иначе у вас будут проблемы, если вам нужно обрабатывать символы, которые не могут быть показаны в латинице. Хотя если вместо этого вы выводите на консоль / консоль CLI, то, конечно, вы должны использовать ту же кодировку, что и кодировка терминала по умолчанию (которая может быть UTF-8 или чем-то еще). Я предпочитаю, чтобы мои терминалы Linux также были настроены как UTF-8.
Других решений пока нет …