Проблема кодировок часто возникает при написании парсеров, чтении данных из xml и CSV файлов. Ниже представлены способы эту проблему решить.
1
windows-1251 в UTF-8
$text = iconv('windows-1251//IGNORE', 'UTF-8//IGNORE', $text);
echo $text;
PHP
$text = mb_convert_encoding($text, 'UTF-8', 'windows-1251');
echo $text;
PHP
2
UTF-8 в windows-1251
$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
echo $text;
PHP
$text = mb_convert_encoding($text, 'windows-1251', 'utf-8');
echo $text;
PHP
3
Когда ни что не помогает
$text = iconv('utf-8//IGNORE', 'cp1252//IGNORE', $text);
$text = iconv('cp1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;
PHP
Иногда доходит до бреда, но работает:
$text = iconv('utf-8//IGNORE', 'windows-1251//IGNORE', $text);
$text = iconv('windows-1251//IGNORE', 'utf-8//IGNORE', $text);
echo $text;
PHP
4
File_get_contents / CURL
Бывают случаи когда file_get_contents()
или CURL возвращают иероглифы (ÐлмазнÑе боÑÑ) – причина тут не в кодировке, а в отсутствии BOM-метки.
$text = file_get_contents('https://example.com');
$text = "\xEF\xBB\xBF" . $text;
echo $text;
PHP
Ещё бывают случаи, когда file_get_contents() возвращает текст в виде:
�mw�Ƒ0�����&IkAI��f��j4/{�</�&�h�� ��({�o�����:/��<g���g��(�=�9�Paɭ
Это сжатый текст в GZIP, т.к. функция не отправляет правильные заголовки. Решение проблемы через CURL:
function getcontents($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
echo getcontents('https://example.com');
PHP
12.01.2017, обновлено 02.11.2021
Другие публикации
Отправка e-mail в кодировке UTF-8 с вложенными файлами и возможные проблемы.
JSON (JavaScript Object Notation) – текстовый формат обмена данными, основанный на JavaScript, который представляет собой набор пар {ключ: значение}. Значение может быть массивом, числом, строкой и…
Описание значений глобального массива $_SERVER с примерами.
Так как Instagram и Fasebook ограничили доступ к API, а фото с открытого аккаунта всё же нужно периодически получать и…
В статье представлены различные PHP-расширения для чтения файлов XLS, XLSX, описаны их плюсы и минусы, а также примеры…
Примеры как зарегистрировать бота в Телеграм, описание и взаимодействие с основными методами API.
Добрый день!
Есть немаленький, старый движок. Чистый код весит около 3 Мб. Около полугода назад успешно перенес его с PHP 5.3 на версию 7.1 — документации по этому делу много. Изучил рекомендации 4-5 хороших статей. И то была пара моментов, которые не были там описаны. В принципе, все прошло достаточно гладко.
Теперь стоит другая задача. Движок настолько старый, что работает с кодировкой Windows-1251. Нужно переделать все под UTF-8. Сколько не искал — ничего толкового из советов не нашел. Большинство хорошей инфы идет из-за бугра, а для них Win-1251 не актуальна.
По сути единственное, что опишут — это заменить все функции работы со строками на их «mb_» аналоги. Я так понимаю, речь идет об этом списке аналогов: php.net/manual/ru/ref.mbstring.php ?
Насколько я понимаю, по части PHP нужно будет еще как минимум задать нужную кодировку в конфиге. Перекодировать сами PHP файлы в UTF-8. БД — то уже отдельные пляски. Еще из нюансов — на сайте есть AJAX, с перекодировкой результатов (т.к. такие запросы, если не ошибаюсь, отправляются только в UTF-8).
Все, этого достаточно? Что еще может быть, у кого есть опыт в подобном деле? И самое главное — нельзя ли просто в настройках PHP указать что «работаем с UTF-8» и точка. Чтобы не менять все функции?
Да и по самим функциям непоняточки. Например, есть preg_replace, но нет mb_preg_replace. Хотя в то же время есть и ereg_replace, и в то же время mb_ereg_replace. Хоть ereg_replace уже устаревшая / удаленная (в зависимости от версии PHP) функция. Как это понимать?
Запутался в конец.
2019.03.07 обновляю: узнал за эти дни много нового и интересного. думаю, многие очень поверхностно относятся к пониманию кодировок. Не знаю, актуальна ли тема на 2019 год. Но если что, в принципе, после всего этого могу сделать большой чек-лист что и как надо делать. Третий день переделываю движок под UTF-8. Реально исправлять код действительно не во многих местах надо. Но точек проверок очень много.
А теперь маленький вопрос-уточнение к знающим людям. Везде про preg_* функции пишут в стиле «используйте модификатор u чтобы работать с юникодом». А когда он реально необходим? По моим наблюдениям, функциям все равно со строками в каких кодировках работать. В PHP отношение ко строкам как к набору байт, а не символов. И походу модификатор u необходимо использовать только когда само регулярное выражение содержит символы за пределами US-ASCII. В противном случае любые UTF-8 строки корректно обрабатываются без модификатора u. Что скажите?
Имеется сайт на PHP, существующий уже много-много лет. Сайт создавался и развивался в кодировке windows-1251, но дальше так жить невозможно, надо весь PHP-код преобразовать в UTF-8, то же самое сделать с html-, css-, js- и прочими файлами, сконвертировать базу данных MySQL и ещё кое-что подправить.
Как быстро выполнить переход сайта на кодировку UTF-8?
Нам помогут знания из статьи про recode и enconv, добавим к ним ещё кое-что.
Все действия можно свести в один bash-скрипт, отдельные части которого рассмотрим в статье.
1. Создать копию всех файлов сайта. Например, сайт находится в /var/www/site. Для работы сайта ещё используются /var/www/dir1, /var/www/dir2, /var/www/dir3, причём dir1 и dir2 надо перекодировать вместе с site, а dir3 не надо трогать. Скопируем всё в /var/www-u8. Для удобства будем использовать переменные, в которых сохраним часто используемые строки.
dir_source=’/var/www’
dir_u8=’/var/www-u8′
cp -R ${dir_source}/* ${dir_u8}
Массив, содержащий имена подкаталогов, в которых надо обработать файлы:
subdirs=(site dir1 dir2)
Во всех подкаталогах надо перекодировать из windows-1251 в UTF-8 все файлы с расширениями: php, txt, js, css, htm. Нам поможет enconv. Затем найти подстроки «windows-1251» или «cp1251» и заменить на «UTF-8». Наконец, найти в php-файлах короткий открывающий тег «<?» и заменить его на полный «<?php». Регулярное выражение для поиска короткого тега ищет строку ‘<?’, после которой следует пробел, конец строки или символ ‘=’ (для файлов, в которых php-код используется вперемешку с html для вставки значений переменных: ‘<?=$var;?>’). Все замены поможет выполнить могучий sed, а с подбором файлов для обработки отлично справится find. Поскольку обработку надо выполнить в нескольких подкаталогах (их имена хранятся в массиве $subdirs), то перебираем элементы массива в цикле (подробнее про использование массивов в bash) и из них составляем путь для поиска командой find.
for item in ${subdirs[*]} do sPath=${dir_u8}/${item} find ${sPath} -iregex '.*\.\(txt\|php\|css\|js\|html?\)' -exec enconv -L russian -x utf8/LF '{}' \; find ${sPath} -iregex '.*\.\(txt\|php\|css\|js\|html?\)' -exec sed -i -r 's/windows-1251|cp1251/UTF-8/ig' '{}' \; find ${sPath} -iname '*\.php' -exec sed -i -r 's/(<\?)(\s|$|=)/<?php\2/ig' '{}' \; done
С перекодировкой базы данных MySQL вообще всё просто. Надо сделать дамп данных, в области описания таблиц заменить строки, определяющие кодировку, загрузить дамп в новую в базу. Примерно так:
HOST_1='localhost' USER_1='user1' PASSWORD_1='password1' DATABASE_1='database1' HOST_2='localhost' USER_2='user2' PASSWORD_2='password2' DATABASE_2='database2' DUMPFILE_1="db-${DATABASE_1}.sql" DUMPFILE_2="db-${DATABASE_2}.sql" # dump from the original DB mysqldump -u ${USER_1} -h ${HOST_1} -p${PASSWORD_1} --opt ${DATABASE_1} > ${DUMPFILE_1} # Replace charset settings from cp1251 to utf8 sed -r 's/CHARSET=cp1251/CHARSET=utf8/ig' ${DUMPFILE_1} > ${DUMPFILE_2} # Load data from the dump mysql -u ${USER_2} -h ${HOST_2} -p${PASSWORD_2} ${DATABASE_2} < ${DUMPFILE_2}
В скрипте все переменные, имена которых оканчиваются на «1», относятся к исходной базе данных, работающей в кодировке cp1251. Все переменные, имена которых оканчиваются на «2», относятся к новой базе данных, которая будет использоваться в перекодированном в utf-8 сайте.
Осталось установить для файлов в ${dir_u8} нужные права доступа, при необходимости настроить контекст безопасности SELinux и, наконец, настроить вебсервер для визуальной проверки перекодированного сайта.
Если свести воедино все фрагменты bash-скрипта, написанные на этой странице, то, фактически, весь процесс изменения кодировки сайта на utf-8 окажется простым и быстрым.
If you need convert string from Windows-1251 to 866. Some characters of 1251 haven't representation on DOS 866. For example, long dash -- chr(150) will be converted to 0, after that iconv finish his work and other charactes will be skiped. Problem characters range in win1251 (128-159,163,165-167,169,171-174,177-182,187-190).
Use this:
//$text - input text in windows-1251
//$cout - output text in 866 (cp866, dos ru ascii)
for($i=0;$i<strlen($text);$i++) {
$ord=ord($text[$i]);
if($ord>=192&&$ord<=239) $cout.=chr($ord-64);
elseif($ord>=240&&$ord<=255) $cout.=chr($ord-16);
elseif($ord==168) $cout.=chr(240);
elseif($ord==184) $cout.=chr(241);
elseif($ord==185) $cout.=chr(252);
elseif($ord==150||$ord==151) $cout.=chr(45);
elseif($ord==147||$ord==148||$ord==171||$ord==187) $cout.=chr(34);
elseif($ord>=128&&$ord<=190) $i=$i; //нет представления данному символу
else $cout.=chr($ord);
}
13 Nov 2016 | Автор: dd |
Перевозил тут пачку сайтов с LAMP на LNAMP, где фронтэндом выступает NGINX. И все бы ничего, если бы не пачка статических сателлитов в кодировке Windows-1251 (cp1251).
Как тут прикололся девака – при анализе сайта, надо сначала чекать кодировку и в случае обнаружения кодировки сайта cp1251 – проверку возраста можно не осуществлять. Но, тем не менее, в инетах до сих пор встречаются такие мастадонты, которые клепают сайты в кодировке CP1251.
Под апачем, при добавлении сайта в ISP Panel это даже не заметишь, а вот при попытке добавить этот же сайт в Vesta CP, получаешь гемор на задницу с крикозябрами. Поэтому надо редактировать конфиг Nginx, предварительно прикрутив туда виндовую кодировку. Но, насколько я помню, у меня этот танец с бубнами не задался и в тот раз, я просто повесил саты на LAMP.
Так что оставалось либо плясать с бубнами вокруг прикручивания виндовой кодировки к NGINX, либо перекодивать файлы в родную для нжинкса UTF-8. Сделать это можно средствами текстового редактора Notepad++ путем перевода кодировки документа и последующего сохранения; либо же в самом линухе. Как я выше заметил, саты статические, то есть на файлах, без использования базы данных. Поэтому перекодировать надо было именно файлы. С базой данных все происходило бы несколько иначе.
Перекодировка файла из CP1251 в UTF-8 производится в консоли через команду iconv
# iconv -f cp1251 -t utf8 FILE-CP1251 -o FILE-UTF8
либо же можно переписать файл в самого себя
# iconv -f cp1251 -t utf8 file.txt -o file.txt
Но поскольку мне надо было перекодировать большое число файлов php, содержащихся в разных папках, то мне пришлось составить небольшое предложение:
# find /path-to-files/ -type f -name \*php -exec iconv -f cp1251 -t utf-8 '{}' -o '{}' \;
Конвертит все в лет.
Для конвертации кодировок есть еще утилита enconv, входящая в состав пакета enca – вот он как раз конвертит сам в себя по умолчанию, перезаписывая файл выходной кодировкой:
# enconv -c file.txt
но, к сожалению, я его не смог подружить с русским языком, т.к даже при указании языка через ключик -L russian скрипт матерился на ошибки. Но с другой стороны, все нормально решилось и через iconv
Rating: 4.4/10 (23 votes cast)
Rating: +1 (from 3 votes)
Смена кодировки сайта из CP1251 на UTF-8, 4.4 out of 10 based on 23 ratings
Теги: centos, сайты