Проблема кодирования Laravel с БД "latin1" - PullRequest
0 голосов
/ 31 января 2019

У меня есть приложение Laravel, которое работает с базой данных с набором символов latin1 (я не могу его изменить).

В моем .env у меня есть следующая конфигурация:

DB_CONNECTION_INTRANET=mysql
DB_HOST_INTRANET=xxxxx
DB_PORT_INTRANET=3306
DB_DATABASE_INTRANET=xxx
DB_USERNAME_INTRANET=xxx
DB_PASSWORD_INTRANET=xxx
DB_CHARSET_INTRANET='latin1'
DB_COLLATION_INTRANET='latin1_swedish_ci'

В config/database.php Я использую эту конфигурацию:

'mysqlIntranet' => [
    'driver'    => env('DB_CONNECTION_INTRANET'),
    'host'      => env('DB_HOST_INTRANET'),
    'port'      => env('DB_PORT_INTRANET'),
    'database'  => env('DB_DATABASE_INTRANET'),
    'username'  => env('DB_USERNAME_INTRANET'),
    'password'  => env('DB_PASSWORD_INTRANET'),
    'unix_socket' => env('DB_SOCKET_INTRANET', ''),
    'charset' => env('DB_CHARSET_INTRANET'),
    'collation' => env('DB_COLLATION_INTRANET'),
],

И модель использует это соединение:

class Cliente extends Model
{
    protected $connection = 'mysqlIntranet';

Когда я выполняю SELECT estado FROM clientes (я работаю с консоли), я получаю следующий результат:

+---------------+
| estado        |
+---------------+
| Informado     |
| Contratación  |

Однако, хотя я настраиваю кодировку в Laravel, при запуске этогокод:

$client = Cliente::query()->first();
$estado = $client->getAttribute('estado');
var_dump($estado . " - " . mb_detect_encoding($estado));
$estado2 = utf8_encode($estado);
var_dump($estado2 . " - " . mb_detect_encoding($estado2));

Я получаю странный результат:

string(20) "Contrataci�n - UTF-8"
string(21) "Contratación - UTF-8"

Я не понимаю, почему конфигурация .env не работает - есть идеи?

====================== ОБНОВЛЕНИЕ ======================
Я попытался смоделировать проблему на местном уровне и обнаружил, что Laravel работает нормально.Я создал эту БД:

CREATE DATABASE my_db CHARACTER SET latin1 COLLATE latin1_swedish_ci;

со значениями .env:

DB_CHARSET_INTRANET="latin1"
DB_COLLATION_INTRANET='latin1_swedish_ci'

и все работало нормально, как и ожидалось.

Я решил попробовать установить следующееКонфигурация на моем сервере:

DB_CHARSET_INTRANET="utf8"
DB_COLLATION_INTRANET='utf8_general_ci'

и, к моему большому удивлению, мне удалось получить значения правильно!

На всякий случай я проверил непосредственно на сервере MySql:

> SELECT * FROM information_schema.SCHEMATA  WHERE schema_name = "xxx";
+--------------+-------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+-------------+----------------------------+------------------------+----------+
| NULL         | xxx         | latin1                     | latin1_swedish_ci      | NULL     |
+--------------+-------------+----------------------------+------------------------+----------+

> SELECT T.table_name, CCSA.* 
  FROM information_schema.`TABLES` T, information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` CCSA 
  WHERE CCSA.collation_name = T.table_collation AND T.table_schema = "xxx";
+-------------+-------------------+--------------------+
| table_name  | COLLATION_NAME    | CHARACTER_SET_NAME |
+-------------+-------------------+--------------------+
| clientes    | latin1_swedish_ci | latin1             |
| clientes_sm | latin1_swedish_ci | latin1             |
+-------------+-------------------+--------------------+

Так что теперь у меня все работает, я хотел бы только понять, почему ...

1 Ответ

0 голосов
/ 01 февраля 2019

mb_detect_encoding нельзя доверять, он часто говорит, что что-то закодировано в utf8, когда это не так.По крайней мере, используйте третий параметр, чтобы сделать его «строгим»: http://php.net/manual/en/function.mb-detect-encoding.php

Метод, которому можно доверять, просматривает отдельные байты.Если - закодирован как один байт, это может быть latin1, если это два байта, это может быть utf8.Функция php bin2hex преобразует строку в шестнадцатеричный формат, и вам будет проще проверить, какие байты она содержит.

Исходя из вашего вывода php, строка определенно закодирована в latin1.Причина, по которой вы видите «Contrataci�n», заключается в том, что программа, которая показывает ваш вывод (консоль? Веб-страница? Просмотр журнала?), Предполагает, что ваш вывод находится в UTF-8, а это не так, это latin1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...