«Кракозябры» в БД или когда «Думать надо было раньше»

в 7:18, , рубрики: php, Администрирование баз данных, базы данных, кодировки, метки: , ,

На днях столкнулся с глупейшей ситуацией. Запустили один веб-проект, все работает, код пишется и дополняется, базы данных наполняются. Разработка идет на тестовом хосте, затем изменения заливаются на сервер, вся проверка сводится к заходу на сам сайт и тесту всего и всея. Вдруг, выясняется, что буква «ш» не отображается на сайте, а вместо неё два ничего не значащих символа.

Та же история оказалась с буквой «И». Тут же заходим в СУБД на сервере и видим… сплошные «кракозябры», вместо кириллицы. Но латиница записывается нормально.

Конечно все подумали на проблемы с кодировками и естественно это так. Смотрим подробнее… Кодировка таблицы — UTF-8, кодировка нужных столбцов — UTF-8, кодировка в заголовках страницы — UTF-8, кодировка в браузере — UTF-8. Ну и конечно подвело промежуточное звено, кодировка соединения — cp1251. А все лишь потому, что не проверили идентичность настроек тестового и рабочего сервера БД. Глупая ошибка, но данных в БД уже полно и надо как-то их вернуть. Прогуглив все, что можно, было найдено несколько интересных sql-запросов, способы с шаманством кодировок в дампах, с помощью блокнота, и один php-скрипт, который отработав безошибочно, просто выдал те же иероглифы. Что то не помогло, что то просто не подходит.

Моё решение банальное, но я не нашел подобного на просторах сети.
Пишем маленький php скрипт перегона нужных таблиц в нужный формат.

<?php
define('BD_HOST','localhost');
define('BD_PASS','password');
define('BD_LOGIN','login');   //доступ к БД
define('BD_FROM','bd1');   //исходная БД
define('BD_IN','bd2');   //конечная БД

$tables = array (	'table1',
					'table2',
					'table3',
					'table4',
					'table5');   //список  нужных таблиц для конвертирования, эти таблицы должны быть как в исходной, так и в конечной БД(в конечной, должны быть пустыми)

foreach ($tables as $table) {
	mysql_connect(BD_HOST,BD_LOGIN,BD_PASS);
	mysql_select_db(BD_FROM);

	$query_select_from = "SELECT * FROM $table;";
	$result = mysql_query($query_select_from);

	mysql_close();   //запросили все косячные данные и закрыли соединение

	mysql_connect(BD_HOST,BD_LOGIN,BD_PASS);
	mysql_select_db(BD_IN);
	mysql_query('set character_set_client="utf8"');
	mysql_query('set character_set_results="utf8"');
	mysql_query('set collation_connection="utf8_general_ci"');
	mysql_query("set names utf8");   //открыли новое соединение, но уже указав все недостающие настройки, из за которых произошло такое недопущение


	while ($t = mysql_fetch_assoc($result)) {
		$values = '';
		$f = false;
		foreach($t as $val) {
			$p = ($f)?',':'';
			$f = true;
			$add = (is_int($val))?"$val":"'$val'";
			$values.= "$p $add";
		};
		$insert_in = "INSERT $table VALUES($values)";
		mysql_query($insert_in);   //запись прочтенной строки, уже в нормальном соединении
	};
	mysql_close();   //закрываем соединение, что бы открыть его уже для другой таблицы.
};

?>

Вот и все. Скрипт сделал именно то, что было нужно и писался за пару минут, поэтому могут быть удивления, что это же можно сделать более гибким и оптимизированным, а еще и ООП неплохо прикрутить бы.

Надеюсь, что данный скрипт пригодится кому-либо.
Спасибо за внимание.

Автор: SaGrok

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js