Като разработчик PHP или MySQL След като прекрачите границите на удобните набори от символи само на английски, бързо се оказвате заплетени в удивително странния свят на UTF-8.
Бърз поглед на грунд UTF-8В работа Преди този започнахме да срещаме проблеми с кодирането на данни, когато показвахме биографии на художници от цял свят. Скоро стана ясно, че има проблеми със съхранените данни, тъй като понякога данните са кодирани правилно, а понякога не.
Това накара програмистите да внедрят комбинация от кръпки, понякога с JavaScript, понякога с мета тагове на HTML кодове, понякога с PHP и т.н. Скоро завършихме със списък с 600 000 биографии на изпълнители, с информация двойно или тройно кодирана, с данни, съхранявани по различни начини, в зависимост от това кой е програмирал функцията или е приложил кръпката. Класическо техническо гнездо за плъхове.
Всъщност навигацията по проблемите на UTF-8 за кодиране на данни може да бъде разочароващо преживяване. Тази публикация предоставя кратка 'готварска книга' за справяне с тези проблеми, по-специално при работа с PHP и MySQL, въз основа на практически опит и научени уроци (и с благодарности, отчасти, на откритата информация тук Y. тук по пътя).
По-конкретно, ще разгледаме следното в тази публикация:
Първото нещо, което трябва да направите, е да модифицирате файла си „php.ini“, за да използвате UTF-8 като набор от символи по подразбиране:
default_charset = 'utf-8';
( Забележка: По-късно можете да използвате phpinfo (), за да проверите дали е зададен правилно ).
Добре, сега PHP и UTF-8 трябва да работят добре заедно. Истина?
Е, не точно. Всъщност те дори не са близо до това.
изпълнител до калкулатор на заплата на пълен работен ден
Въпреки че тази промяна ще гарантира, че PHP винаги извежда UTF-8 като кодиране на символи (в типови заглавия - съдържание на отговора на браузъра), все пак трябва да направите няколко модификации на вашия PHP код, за да сте сигурни, че обработва и генерира UTF-8 символи правилно .
Свързани: Най-добри практики и съвети за PHP от разработчиците на ApeeScapeЗа да сте сигурни, че вашият PHP код се справя добре в пясъчника за кодиране на данни UTF-8, ето нещата, които трябва да направите:
Задайте UTF-8 като набор от символи за всички изходи на заглавката от вашия PHP код.
Във всеки PHP изходен заглавие посочете UTF-8 като кодиране:
заглавка (‘Content-Type: text / html; charset = utf-8’);
Посочете UTF-8 като тип кодиране за XML
function utf8_for_xml($string) { return preg_replace('/[^x{0009}x{000a}x{000d}x{0020}-x{D7FF}x{E000}-x{FFFD}]+/u', ' ', $string); }
Премахнете неподдържаните символи от XML
Тъй като не всички UTF-8 символи се приемат в XML документ, трябва да премахнете всякакъв тип знаци от всеки XML, който генерирате. Полезна функция за това (която намерих тук) е следната:
$safeString = utf8_for_xml($yourUnsafeString);
Ето как можете да използвате тази функция във вашия код:
htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8')
Посочете UTF-8 като набор от символи за цялото HTML съдържание
За HTML съдържание посочете UTF-8 като кодиране:
default_charset
В HTML формите посочете UTF-8 като кодиране:
htmlspecialchars
Посочете UTF-8 като кодиране за всички повиквания към htmlspecialchars
Например:
htmlentities
Забележка: От PHP 5.6.0 стойността mysql_set_charset
се използва по подразбиране. Към PHP 5.4.0 по подразбиране се използва UTF-8, но преди PHP 5.4.0 като подразбиране се използва ISO-8859-1. Следователно е добра идея винаги да се посочва изрично UTF-8, за да бъде в безопасност, въпреки че този аргумент е технически незадължителен.
как да уча за сертифициране по aws
Също така имайте предвид, че за UTF-8, $link = mysql_connect('localhost', 'user', 'password'); mysql_set_charset('utf8', $link);
Y. mysql_set_charset
те могат да се използват взаимозаменяемо.
Посочете UTF-8 като набор от символи по подразбиране, който да се използва при обмен на данни с базата данни MySQL, като се използва mysqli::set_charset
:
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'test'); /* check connection */ if (mysqli_connect_errno()) { printf('Connect failed: %s
', mysqli_connect_error()); exit(); } /* change character set to utf8 */ if (!$mysqli->set_charset('utf8')) { printf('Error loading character set utf8: %s
', $mysqli->error); } else { printf('Current character set: %s
', $mysqli->character_set_name()); } $mysqli->close();
Имайте предвид, че към PHP 5.5.0, iconv
е оттеглено и iconv_strlen
трябва да се използва вместо:
mbstring
Има няколко PHP функции, които може да се провалят или поне да не се държат според очакванията, ако представянето на символа се нуждае от повече от 1 байт (както UTF-8 прави). Пример е функцията strlen, която ще върне броя на байтовете вместо броя на символите.
Има две възможности за справяне с това:
Функциите [mysql] default-character-set=UTF-8 [mysqld] character-set-client-handshake = false #force encoding to uft8 character-set-server=UTF-8 collation-server=UTF-8_general_ci [mysqld_safe] default-character-set=UTF-8
налични по подразбиране с PHP, предоставят съвместими многобайтови версии на много от тези функции (например my.ini
и др.). Не забравяйте обаче, че низовете, които предоставяте на тези функции, от своя страна трябва да бъдат кодирани правилно.
Има и разширението mysql> show variables like 'char%';
към PHP (налична е информация за активиране и конфигуриране тук ). Това разширение предоставя пълен набор от функции, които адекватно обслужват многобайтово кодиране.
От страна на нещата MySQL / UTF-8 се изискват модификации на файла my.ini, както следва:
Задайте следните конфигурационни параметри след всеки съответния таг: [client] default-character-set = UTF-8
| character_set_client | UTF-8 | character_set_connection | UTF-8 | character_set_database | UTF-8 | character_set_filesystem | binary | character_set_results | UTF-8 | character_set_server | UTF-8 | character_set_system | UTF-8 | character_sets_dir | /usr/share/mysql/charsets/
След като направите горните промени във вашия set names UTF-8;
файл, рестартирайте демона MySQL.
За да проверите дали всичко е конфигурирано правилно за използване на UTF-8 кодиране, изпълнете следната заявка:
sphinx.conf
Резултатът трябва да бъде нещо подобно:
charset_type = utf-8
Ако вместо това видите latin1, изброени за някое от тях, проверете конфигурацията си и се уверете, че сте рестартирали успешно MySQL Daemon.
MySQL UTF-8 всъщност е частично изпълнение на набора от символи UTF-8. По-конкретно, кодирането на данни MySQL UTF-8 използва максимум 3 байта, докато 4 байта са необходими за кодиране на пълния набор от UTF-8 символи. Това е добре за всички символи на езика, но ако трябва да поддържате астрални символи (чиито кодови точки варират от U + 010000 до U + 10FFFF), те изискват четирибайтово кодиране, което не може да се поддържа в MySQL UTF-8. В MySQL 5.5 0.3 това беше обсъдено с добавяне на поддръжка на набор от символи utf8mb4 , който използва максимум четири байта на символ и следователно поддържа пълния набор от знаци UTF-8. Така че, ако използвате MySQL 5.5.3 или по-нова версия, използвайте utf8mb4 вместо UTF-8 като набор от символи за база данни / таблица / ред. Повече информация можете да намерите тук.
Ако свързващият клиент няма начин да посочи кодирането за комуникацията си с MySQL, след като връзката бъде установена, може да се наложи да изпълните следната команда / заявка:
sql_query_pre = SET CHARACTER_SET_RESULTS=UTF-8
Когато определяте размера на полетата на varchar, когато моделирате вашата база данни, не забравяйте, че UTF-8 символите могат да изискват до 4 байта на символ.
В конфигурационния файл на Sphinx (т.е. sql_query_pre = SET NAMES UTF-8
):
Задайте дефиницията на индекса си така:
charset_table
Добавете следното към дефиницията на шрифта:
javascript получава текущото време в милисекунди
ALTER SCHEMA `your-db-name` DEFAULT CHARACTER SET UTF-8;
mysql> show variables like 'char%';
Рестартирайте двигателя и повторете всички индекси.
Ако искате да конфигурирате Сфинкса така, че буквите като C c Ć ć Ĉ ĉ Ċ ċ Č č да се третират като едни и същи за целите на търсенето, ще трябва да конфигурирате mysqldump -u USERNAME -pDB_PASSWORD --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert DATABASENAME --tables TABLENAME > DUMP_FILE_TABLE.sql
(известен също като сгъване на символи), което по същество представлява картографиране между символи. Налична е повече информация тук .
Ако имате съществуваща база данни, вече кодирана в latin1, ето как да конвертирате latin1 в UTF-8:
Уверете се, че сте направили всички модификации на конфигурационните настройки във вашия файл my.ini, както е описано по-горе.
Изпълнете следната команда:
mysqldump -u root --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert artists-database --tables tbl_artist > tbl_artist.sql
Чрез командния ред проверете дали всичко е конфигурирано правилно за UTF-8
perl -i -pe 's/DEFAULT CHARSET=latin1/DEFAULT CHARSET=UTF-8/' DUMP_FILE_TABLE.sql
Създайте dump файл в кодиране latin1 за таблицата, която искате да конвертирате:
mysql> source 'DUMP_FILE_TABLE.sql';
Пример:
mysql> select count(*) from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD);
Направете глобално търсене и замяна на набора от символи във файла на дъмп от latin1 на UTF-8:
Например, като използвате Perl:
create table temptable ( select * from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD));
Забележка за потребители на Windows: Този низ за замяна на набори от символи (latin1 до UTF-8) може да се извърши и с помощта на find and replace в WordPad (или друг текстов редактор, като vim). Не забравяйте да запазите файла, както е (не като текстов файл в Unicode!).
От този момент нататък ще започнем да се забъркваме с данните от базата данни, така че вероятно би било разумно да направите резервно копие на базата данни, ако все още не сте го направили. След това възстановете дъмп в базата данни:
на какъв език за програмиране се пише windows
alter table temptable modify temptable.ArtistName varchar(128) character set latin1;
Намерете всички записи, които не са преобразувани правилно, и ги коригирайте. Тъй като символите, които не са ASCII, са многобайтови по дизайн, можем да ги намерим, като сравним дължината на байта с дължината на символа (т.е. да идентифицираме редове, които могат да съдържат двойни UTF-8 символа). Кодирани, които трябва да бъдат коригирани).
Вижте дали има записи с многобайтови символи (ако тази заявка връща нула, тогава в таблицата не трябва да има записи с многобайтови символи и можете да преминете към стъпка 8).
ArtistName
Копирайте редове с многобайтови символи във временна таблица:
alter table temptable modify temptable.ArtistName blob; alter table temptable modify temptable.ArtistName varchar(128) character set UTF-8;
Преобразува двойно кодирани UTF-8 знака в подходящи UTF-8 знака.
Това всъщност е малко сложно. Низът с двойно кодиране е този, който е бил правилно кодиран като UTF-8. Тогава обаче MySQL ни направи грешна услуга да го преобразуваме (от това, което смяташе, че е latin1) отново в UTF-8, когато зададохме колоната на UTF-8 кодиране. Решаването на това, следователно, изисква процес от две стъпки, чрез който „изневеряваме“ на MySQL, за да не го направим в тази „услуга“.
Първо, задаваме типа кодиране за колоната обратно на latin1, като по този начин елиминираме двойното кодиране:
Пример:
delete from MY_TABLE where LENGTH(MY_FIELD) = CHAR_LENGTH(MY_FIELD);
Забележка: Уверете се, че сте използвали правилния тип поле за вашата таблица. В горния пример за нашата таблица, правилният тип поле за replace into MY_TABLE (select * from temptable);
беше varchar (128), но полето на таблицата може да бъде текстово или друг вид. Уверете се, че сте го посочили правилно.
Проблемът е, че сега, ако зададем кодирането на колоната обратно на UTF-8, MySQL отново ще стартира кодиране на данни latin1 до UTF-8 и ще се върнем там, откъдето започнахме. За да се избегне това, типът на колоната се променя на blob и след това се настройва на UTF-8. Това използва факта, че MySQL няма да се опитва да кодира blob. И така, можем да „измамим“ преобразуването на набора от символи MySQL, за да избегнем проблема с двойното кодиране.
Пример:
изградете своя собствена метеорологична станция
|_+_|
(Отново, както беше отбелязано по-горе, не забравяйте да използвате подходящия тип поле за вашата таблица.)
Изтрийте редове само с еднобайтови символи, принадлежащи към временната таблица:
Поставете отново фиксираните редове в оригиналната таблица (преди да направите това, трябва да изпълните някои селекти на временната таблица, за да проверите дали е била правилно коригирана, само като предпазна мярка).
|_+_|
Друго нещо, което трябва да запомните и проверите, е, че файловете с изходен код, ресурсните файлове и т.н. се записват правилно с UTF-8 кодиране на данни. В противен случай всички 'специални' знаци в тези файлове може да не се обработват правилно.
Например в Netbeans можете да щракнете с десния бутон върху вашия проект, да изберете свойства и след това под „Източници“ ще намерите опцията за кодиране на данни (обикновено по подразбиране е UTF-8, но е по-добре да проверите).
Или в Windows Notepad, използвайте опцията „Запазване като ...“ в менюто Файлове и изберете опцията за кодиране UTF-8 в долната част на диалоговия прозорец. (Обърнете внимание, че опцията „Unicode“, която Notepad предлага, всъщност е UTF-16 и това не е това, което искате.)
Въпреки че може да е досадно, отделянето на време за преглед на тези стъпки за системно решаване на проблемите с кодирането на данни в MySQL и PHP UTF-8 може да ви спести много време. В дългосрочен план този вид методичен подход е далеч по-добър от общата тенденция за корекция на системата.
Надявам се, че това ръководство подчертава важността на разглеждането на дефиницията на набора от данни при първоначална настройка на среда на проект и работа в среда на софтуерни проекти, която взема предвид кодирането на символи при манипулирането на текст и низове.
Свързани: Преди да отстраните грешки в PHP, който не работи, консултирайте се с този списък с 10-те най-често срещани грешки, които PHP разработчиците правят, преди да отстраните грешки в PHP, който не работи, проверете списъка с 10-те най-често срещани грешки, които PHP разработчиците правят.