PHP - плохо закодированные турецкие символы в базе данных MySQL

Я работаю над турецким веб-сайтом, на котором в базе данных MySQL хранится много искаженных турецких символов, например:

 - ş as þ
 - ı as ý
 - ğ as ð
 - Ý as İ

я не могу изменить данные в базе данных, потому что база данных обновляется ежедневно, и новые данные снова будут содержать неверные символы. Итак, моя идея заключалась в том, чтобы изменить данные в PHP вместо изменения данных в базе данных. Я пробовал несколько шагов:

Неправильно отображаются турецкие символы

Исправить проблему с турецкой кодировкой Html/PHP (iconv?)

Проблема с отображением турецкого языка PHP

Проблема с кодировкой PHP MYSQL (турецкие символы)

Я использую PHP-MySQLi-Database-Class, доступный на GitHub с utf8. как кодировка.

Я даже пытался заменить искаженные символы на str_replace, например:

$newString = str_replace ( chr ( 253 ), "ı", $newString );

Мой вопрос, как я могу решить проблему, не меняя символы в базе данных? Есть ли передовой опыт? Это хороший вариант просто заменить символы?

EDIT: решил это с помощью

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-9" />

person Doğan Uçar    schedule 25.11.2015    source источник
comment
Вы определили, какой неверный набор символов использовался для записи значений в базу данных? Вы можете попытаться установить для character_set_client неправильный набор символов, прочитать данные, а затем записать данные обратно, используя правильный.   -  person 0xCAFEBABE    schedule 25.11.2015
comment
Вы имеете в виду выбор, преобразование и вставку в таблицы?   -  person Doğan Uçar    schedule 25.11.2015
comment
Судя по тому, что вы описываете, кодировка была неправильной, когда кто-то вставлял данные в базу данных. Наиболее последовательный способ исправить это — использовать ту же кодировку для обратного чтения ошибочно закодированных данных, а затем перезаписать их в базу данных с правильной кодировкой.   -  person 0xCAFEBABE    schedule 26.11.2015
comment
Спасибо. Но в настоящее время я решил это, изменив HTML-тег meta charset на iso-8859-9.   -  person Doğan Uçar    schedule 01.12.2015
comment
Укажите SELECT col, hex(col) FROM tbl WHERE ..., чтобы мы могли увидеть, что было сохранено. Кроме того, SHOW CREATE TABLE   -  person Rick James    schedule 11.12.2015


Ответы (2)


Два решения хороши

Проблема с кодировкой PHP MYSQL (турецкие символы)

Проблема с отображением турецкого языка PHP

Также вы можете установить конфигурацию в phpMyAdmin.

Операции> Параметры таблицы> Сопоставление> выберите utf8_general_ci

если вы создаете таблицы, уже редактируйте структуры сопоставления

person Fahed Alkaabi    schedule 25.11.2015
comment
обратите внимание, что значения неправильно хранятся в базе данных, поэтому первое решение неприменимо. Я также добавил все метатеги в html. - person Doğan Uçar; 25.11.2015
comment
попробуйте восстановить данные после редактирования сопоставления на MySql - person Fahed Alkaabi; 26.11.2015
comment
Спасибо. Но в настоящее время я решил это, изменив кодировку на iso-8859-9. Возможно позже я изменю сортировку - person Doğan Uçar; 01.12.2015

SELECT CONVERT(CONVERT(UNHEX('d0dddef0fdfe') USING ...) USING utf8);

latin5 / iso-8859-1 показывает ĞİŞğış
latin1 / iso-8859-9 показывает ÐÝÞðýþ

Вы путаете две похожие кодировки; см. первый абзац в https://en.wikipedia.org/wiki/ISO/IEC_8859- 9 .

«Сортировка» предназначена только для сортировки. Но сначала вам нужно изменить CHARACTER SET на latin5. Затем измените сопоставление на latin5_turkish_ci. (Поскольку это значение по умолчанию для latin5, никаких действий предпринимать не нужно.)

Этого может быть достаточно, чтобы внести изменения в MySQL: EDIT 3

NO, this is probably wring -- ALTER TABLE tbl CONVERT TO CHARACTER SET latin5;

Увидев больше проблем, это "двухэтапное ALTER", вероятно, правильно:

ALTER TABLE Tbl MODIFY COLUMN col VARBINARY(...) ...;
ALTER TABLE Tbl MODIFY COLUMN col VARCHAR(...) ... CHARACTER SET latin5 ...;

Сделайте это для каждой таблицы. Обязательно сначала проверьте это на копии ваших данных.

двухэтапный оператор ALTER полезен, когда байты верны, а CHARACTER SET нет.

CONVERT TO следует использовать, когда символы правильные, но вам нужна другая кодировка (и CHARACTER SET). См. Случай 5.

Изменить 1

E7 и FD и cp1250, dec8, latin1 и latin2 для ç и ý. FD на латыни5 это ı. Я делаю вывод, что ваша кодировка latin1, а не latin5.

Вы говорите, что не можете изменить «сценарии». Давайте посмотрим на ваши ограничения. Вы ограничены на стороне INSERT? Или сторона SELECT? Или оба? Что такое рендеринг текста; HTML? MySQL готов перейти с latin1 на/с latin5, и вы вставляете/выбираете (на основе нескольких настроек). И/или вы можете солгать HTML (через метатег), чтобы заставить его интерпретировать байты по-другому. Уточните детали потока данных.

Изменить 2

Учитывая, что шестнадцатеричное число в таблице равно E7FD6B6172FD6C6D6173FD6E61, и оно должно отображаться как çıkarılmasına, ... Обратите внимание, что вторая буква должна отображаться как ı (маленькая I без точек по-турецки), а не ý (маленькая Y с острым знаком), верно?

Начните с попытки

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-9"/>

Это должно дать вам рендеринг `latin5, как вы уже выяснили. Справочник IANA.

Что касается «Оптимальной практики», это будет включать изменение способа вставки текста. Вы заявили, что это запрещено.

По-видимому, у вас есть символы latin5, хранящиеся в столбце latin1. Поскольку latin1 не требует проверки, вы можете без проблем вставлять и извлекать символы latin5.

Это не относится к желанию иметь турецкую сортировку. Если необходимо, я, вероятно, смогу придумать способ указать турецкий порядок для конкретных утверждений; просьба предоставить образец заявления.

person Rick James    schedule 11.12.2015
comment
изменить таблицу на latin5 не удается. Ошибка: Код ошибки: 1366. Неверное строковое значение: '\xFEand\xFD....' для заголовка столбца в строке 1 в настоящее время, я использую HTML-тег метакодировки для iso-8859-9 в HTML, и это работает.. но я не знаю, хорошее это решение или нет - person Doğan Uçar; 29.12.2015
comment
Хммм... Давайте сделаем резервную копию и кое-что проверим. Пожалуйста, выполните SELECT col, HEX(col) FROM tbl WHERE ..., чтобы показать, что что-то выходит "не так". И укажите, что вы ожидаете от этого столбца для этой строки. - person Rick James; 30.12.2015
comment
Проблема в том, что значения плохо закодированы, хранящиеся в таблицах. Я могу только изменить таблицы, но не могу изменить сценарии, которые вставляют данные... Пример: col: 'Ekonomik krizin faturasýný kendilerine çýkarýlmasýna kýzan emekçiler, sokaða çýkarak tepki gösterdi.', hex(col):' 456B6F6E6F6D696B206B72697A696E2066617475726173FD6EFD206B656E64696C6572696E6520E7FD6B6172FD6C6D6173FD6E61206BFD7A616E20656D656BE7696C65722C20736F6B61F06120E7FD6B6172616B207465706B692067F67374657264692E» - person Doğan Uçar; 31.12.2015
comment
я ограничен на стороне вставки. У меня нет доступа к сценариям, которые вставляют данные. На стороне выбора я могу делать то, что хочу. Текст визуализируется HTML. это звучит интересно. Так что я должен изменить сейчас на latin1? каковы следующие шаги? - person Doğan Uçar; 04.01.2016
comment
Во-первых, позвольте мне увидеть SHOW CREATE TABLE, чтобы я знал, какой набор символов установлен для столбца. - person Rick James; 04.01.2016
comment
эй, извините мой поздний ответ. SHOW CREATE TABLE слишком длинный для публикации в качестве комментария, достаточно ли этого, чтобы увидеть это?: ENGINE=MyISAM AUTO_INCREMENT=48501 DEFAULT CHARSET=latin1 - person Doğan Uçar; 08.01.2016
comment
Эй, Рик, так что ты прав. С указанным выше метатегом я могу отображать турецкие символы. Но невозможно использовать строки, например, для json_encode(). Как это решить? - person Doğan Uçar; 08.01.2016
comment
JSON нужен utf8, а не latin1. - person Rick James; 08.01.2016
comment
Метатег заставляет его работать, но это кладж. - person Rick James; 08.01.2016
comment
Я включил вашу проблему в свой том с кодировкой: mysql.rjweb.org/doc.php/ charcoll#турецкий - person Rick James; 08.01.2016
comment
Итак, вы имеете в виду, что единственный способ получить чистую базу данных - это изменить способ ее вставки? спасибо, что включили мою проблему. А что сейчас происходит с проблемой xD - person Doğan Uçar; 09.01.2016
comment
Правильное решение - полностью использовать latin5 или полностью utf8 (utf8 также позволяет работать json). Полностью означает, что байты закодированы таким образом, и соединение установлено таким образом, и таблица (или, по крайней мере, соответствующие столбцы) закодированы таким образом и метатег именно такой. - person Rick James; 09.01.2016
comment
В настоящее время вам повезло, что latin1 и latin5 на самом деле не заботятся о том, как выглядят байты. Итак, тот факт, что вы смешали latin1 и latin5, не повредит; метатег спасает положение. - person Rick James; 09.01.2016
comment
Хорошо, большое спасибо, Рик.. но у меня есть последний вопрос.. допустим, я изменю способ вставки данных и изменю кодировку столбцов, таблиц и баз данных.. как я могу изменить плохо закодированные/отформатированные символы (как я могу преобразовать çýkarýlmasýna в çıkarılmasına?) - person Doğan Uçar; 10.01.2016
comment
Что ж, в этом вся прелесть. latin1 (и cp1250, dec8, latin2) ý закодирован в шестнадцатеричном формате FD. latin5 ı также кодируется FD. То есть байты в вашей таблице правильные; просто их интерпретация приводит к неправильному символу. Я думаю, что правильный способ изменить определение столбца с latin1 на latin5 без изменения байтов — это использовать 2-этапное ALTER. - person Rick James; 10.01.2016
comment
Мне жаль, что это занимает так много времени. Есть 4 шага, чтобы сделать это правильно; это означает, по крайней мере, 15 комбинаций того, как сделать это неправильно. Нетривиально выяснять, что пошло не так. И в вашем случае неправильное использование latin1 в некоторых или во всех первых трех шагах не влияет на результат. Четвертый шаг (метатег) устранил проблему, но оставил нас с вами в недоумении относительно того, что происходит. - person Rick James; 10.01.2016
comment
latin5 охватывает турецкий и английский языки, но не более того. Если вам когда-нибудь понадобится больше, вам нужно будет перейти на utf8 (или utf8mb4). В этот момент все 4 шага должны быть синхронизированы, чтобы получить ı без точек и т. д. - person Rick James; 10.01.2016
comment
Я вижу, что дал вам неправильный совет (не зная всех 4 шагов). См. Редактировать 3. - person Rick James; 10.01.2016