Kot razvijalec PHP ali MySQL Ko prestopite meje udobnih naborov znakov samo v angleščini, se hitro znajdete zapleteni v čudovito čudnem svetu UTF-8.
Hiter pogled na UTF-8 PrimerV delo Pred tem smo se pri prikazovanju biografij umetnikov z vsega sveta začeli srečevati s težavami pri kodiranju podatkov. Kmalu se je pokazalo, da obstajajo težave s shranjenimi podatki, saj so bili podatki včasih pravilno kodirani, včasih pa ne.
To je vodilo programerje k izvedbi mešanice popravkov, včasih z JavaScriptom, včasih z metaoznakami nabora HTML, včasih s PHP itd. Kmalu smo končali s seznamom 600.000 biografij umetnikov z informacijami, ki so bile dvo- ali trikrat kodirane, podatki pa so bili shranjeni na različne načine, odvisno od tega, kdo je funkcijo programiral ali uporabil popravek. Klasično tehnično gnezdo podgan.
Dejansko je navigacija po težavah UTF-8, povezanih s kodiranjem podatkov, lahko frustrirajoča izkušnja. Ta objava vsebuje jedrnato 'kuharsko knjigo' za reševanje teh vprašanj, zlasti pri delu s PHP in MySQL, na podlagi praktičnih izkušenj in pridobljenih spoznanj (in delno zahvaljujoč odkritim informacijam tukaj Y. tukaj na poti).
Natančneje bomo v tej objavi zajeli naslednje:
Najprej morate spremeniti datoteko 'php.ini', da bo kot privzeti nabor znakov uporabljal UTF-8:
default_charset = 'utf-8';
( Opomba: Kasneje lahko s pomočjo phpinfo () preverite, ali je pravilno nastavljen ).
V redu, PHP in UTF-8 bi morala dobro sodelovati. Resnica?
No, ne ravno. Pravzaprav tega niti približno ne počnejo.
Čeprav bo ta sprememba zagotovila, da bo PHP vedno izpisal UTF-8 kot kodiranje znakov (v glavah vrst - vsebina odziva brskalnika), morate še vedno spremeniti svojo kodo PHP, da zagotovite pravilno obdelavo in ustvarjanje znakov UTF-8 .
Sorodno: Najboljši postopki in nasveti PHP razvijalcev ApeeScapeDa bi zagotovili, da se vaša koda PHP dobro obnaša v peskovniku za kodiranje podatkov UTF-8, morate storiti naslednje:
Nastavite UTF-8 kot nabor znakov za vse izhode glave s kodo PHP.
V vsaki izhodni glavi PHP kot kodiranje določite UTF-8:
glava (‘Content-Type: text / html; charset = utf-8’);
Kot vrsto kodiranja za XML določite UTF-8
function utf8_for_xml($string) { return preg_replace('/[^x{0009}x{000a}x{000d}x{0020}-x{D7FF}x{E000}-x{FFFD}]+/u', ' ', $string); }
Odstranite nepodprte znake iz XML
Ker v dokumentu XML niso sprejeti vsi znaki UTF-8, morate iz katerega koli XML, ki ga ustvarite, odstraniti katero koli vrsto znakov. Koristna funkcija za to (ki sem jo našel tukaj) je naslednja:
najboljše pisave brez serifa za tisk
$safeString = utf8_for_xml($yourUnsafeString);
Tu funkcijo lahko uporabite v svoji kodi:
htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8')
Kot nabor znakov za vso vsebino HTML določite UTF-8
Za vsebino HTML za kodiranje navedite UTF-8:
default_charset
V obrazcih HTML kot kodiranje navedite UTF-8:
htmlspecialchars
Kot kodiranje za vse klice htmlspecialchars določite UTF-8
Na primer:
htmlentities
Opomba: V PHP 5.6.0 je vrednost mysql_set_charset
se uporablja privzeto. Od PHP 5.4.0 je privzeto prišel UTF-8, pred PHP 5.4.0 pa je bil privzeto uporabljen ISO-8859-1. Zato je dobro, da UTF-8 vedno izrecno določite, da je varen, čeprav je ta argument tehnično neobvezen.
Upoštevajte tudi, da je za UTF-8 $link = mysql_connect('localhost', 'user', 'password'); mysql_set_charset('utf8', $link);
Y. mysql_set_charset
lahko jih uporabljamo medsebojno.
Kot privzeti nabor znakov določite UTF-8 za izmenjavo podatkov z bazo podatkov MySQL z uporabo 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();
Upoštevajte, da od PHP 5.5.0, iconv
je zastarel in iconv_strlen
namesto tega uporabite:
vlagajte v podjetja z elon mošusom
mbstring
Obstaja več funkcij PHP, ki se lahko zrušijo ali se vsaj ne obnašajo, kot je bilo pričakovano, če predstavljanje znakov potrebuje več kot 1 bajt (tako kot UTF-8). Primer je funkcija strlen, ki bo vrnila število bajtov namesto števila znakov.
Na voljo sta dve možnosti:
Funkcije [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
ki so privzeto na voljo s PHP, ponujajo združljive večbajtne različice številnih teh funkcij (na primer my.ini
itd.). Ne pozabite pa, da morajo biti nizi, ki jih dobavljate tem funkcijam, pravilno kodirani.
Obstaja tudi podaljšek mysql> show variables like 'char%';
na PHP (na voljo so informacije o aktivaciji in konfiguraciji tukaj ). Ta razširitev ponuja celoten nabor funkcij, ki zadovoljivo skrbi za večbajtno kodiranje.
Na strani MySQL / UTF-8 so potrebne spremembe datoteke my.ini, kot sledi:
Za vsako ustrezno oznako nastavite naslednje konfiguracijske parametre: [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/
Po izvedbi zgornjih sprememb v datoteki set names UTF-8;
znova zaženite demon MySQL.
Če želite preveriti, ali je bilo vse pravilno konfigurirano za uporabo kodiranja UTF-8, zaženite naslednjo poizvedbo:
sphinx.conf
Rezultat bi moral biti približno tak:
charset_type = utf-8
Če namesto tega za katero koli od njih vidite latin1, preverite svojo konfiguracijo in se prepričajte, da ste uspešno znova zagnali MySQL Daemon.
MySQL UTF-8 je pravzaprav delna izvedba nabora znakov UTF-8. Natančneje, kodiranje podatkov MySQL UTF-8 uporablja največ 3 bajte, medtem ko so za kodiranje celotnega nabora znakov UTF-8 potrebni 4 bajti. To je v redu za vse znake v jeziku, če pa morate podpirati astralne simbole (katerih kodne točke se gibljejo od U + 010000 do U + 10FFFF), zahtevajo štiribajtno kodiranje, ki ga MySQL UTF-8 ne podpira. V MySQL 5.5 0.3 smo o tem razpravljali z dodatkom podpore nabora znakov utf8mb4 , ki uporablja največ štiri bajte na znak in zato podpira celoten nabor znakov UTF-8. Torej, če uporabljate MySQL 5.5.3 ali novejšo različico, uporabite utf8mb4 namesto UTF-8 kot nabor znakov baze podatkov / tabele / vrstice. Več informacij je na voljo tukaj.
Če povezovalni odjemalec ne more določiti kodiranja za svojo komunikacijo z MySQL, bo po vzpostavitvi povezave morda treba zagnati naslednji ukaz / poizvedbo:
sql_query_pre = SET CHARACTER_SET_RESULTS=UTF-8
Pri določanju velikosti polj varchar pri modeliranju baze podatkov ne pozabite, da znaki UTF-8 lahko zahtevajo do 4 bajte na znak.
V konfiguracijski datoteki Sphinx (tj. sql_query_pre = SET NAMES UTF-8
):
V definiciji indeksa nastavite na:
charset_table
V definicijo pisave dodajte naslednje:
ALTER SCHEMA `your-db-name` DEFAULT CHARACTER SET UTF-8;
mysql> show variables like 'char%';
Znova zaženite motor in ponovite vse indekse.
Če želite sfingo konfigurirati tako, da so črke, kot je C c Ć ć Ĉ ĉ Ċ ċ Č č, za namene iskanja obravnavane kot enake, boste morali konfigurirati mysqldump -u USERNAME -pDB_PASSWORD --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert DATABASENAME --tables TABLENAME > DUMP_FILE_TABLE.sql
(znano tudi kot zlaganje znakov), kar je v bistvu preslikava med znaki. Na voljo je več informacij tukaj .
Če imate obstoječo bazo podatkov, ki je že kodirana v latin1, vam tukaj pokažem, kako pretvoriti latin1 v UTF-8:
Prepričajte se, da ste v datoteki my.ini izvedli vse spremembe konfiguracijskih nastavitev, kot je opisano zgoraj.
Zaženite naslednji ukaz:
mysqldump -u root --opt --skip-set-charset --default-character-set=latin1 --skip-extended-insert artists-database --tables tbl_artist > tbl_artist.sql
V ukazni vrstici preverite, ali je vse pravilno konfigurirano za UTF-8
perl -i -pe 's/DEFAULT CHARSET=latin1/DEFAULT CHARSET=UTF-8/' DUMP_FILE_TABLE.sql
Ustvarite datoteko izpisa v kodiranju latin1 za tabelo, ki jo želite pretvoriti:
mysql> source 'DUMP_FILE_TABLE.sql';
Primer:
kako narediš neskladnega bota
mysql> select count(*) from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD);
Naredite globalno iskanje in zamenjavo nabora znakov v datoteki izpisa z latin1 na UTF-8:
Na primer z uporabo Perla:
create table temptable ( select * from MY_TABLE where LENGTH(MY_FIELD) != CHAR_LENGTH(MY_FIELD));
Opomba za uporabnike sistema Windows: Nadomestni niz tega nabora znakov (latin1 na UTF-8) lahko izvedete tudi z iskanjem in zamenjavo v programu WordPad (ali katerem koli drugem urejevalniku besedil, kot je vim). Datoteko shranite takšno, kot je (ne kot besedilno datoteko Unicode!).
Od tega trenutka se bomo začeli zapletati s podatki baze podatkov, zato bi bilo verjetno pametno narediti varnostno kopijo baze podatkov, če tega še niste storili. Nato obnovite izpis v zbirki podatkov:
alter table temptable modify temptable.ArtistName varchar(128) character set latin1;
Poiščite vse zapise, ki niso bili pravilno pretvorjeni, in jih popravite. Ker so znaki, ki niso ASCII, večbajtni po svoji zasnovi, jih lahko najdemo s primerjavo dolžine bajta z dolžino znaka (torej za prepoznavanje vrstic, ki lahko vsebujejo dvojne znake UTF-8), kodirane, ki jih je treba popraviti).
Preverite, ali obstajajo zapisi z večbajtnimi znaki (če ta poizvedba vrne nič, potem v tabeli ne sme biti zapisov z večbajtnimi znaki in lahko nadaljujete do 8. koraka).
ArtistName
Kopirajte vrstice z večbajtnimi znaki v začasno tabelo:
alter table temptable modify temptable.ArtistName blob; alter table temptable modify temptable.ArtistName varchar(128) character set UTF-8;
Pretvori dvojno kodirane znake UTF-8 v ustrezne znake UTF-8.
To je pravzaprav nekoliko zapleteno. Niz z dvojnim kodiranjem je tisti, ki je bil pravilno kodiran kot UTF-8. Vendar nam je MySQL nato naredil napačno uslugo in ga znova pretvoril (iz tistega, kar se mu je zdelo latin1) v UTF-8, ko smo stolpec nastavili na kodiranje UTF-8. Da bi to rešili, je torej potreben postopek v dveh korakih, s katerim 'goljufamo' MySQL, da bi nam preprečili, da bi nam naredil to 'uslugo'.
Najprej nastavimo vrsto kodiranja za stolpec nazaj na latin1 in tako odpravimo dvojno kodiranje:
Primer:
delete from MY_TABLE where LENGTH(MY_FIELD) = CHAR_LENGTH(MY_FIELD);
Opomba: Uporabite pravilno vrsto polja za tabelo. V zgornjem primeru je za našo tabelo pravilna vrsta polja za replace into MY_TABLE (select * from temptable);
je bil varchar (128), vendar je polje tabele lahko besedilno ali katero koli drugo vrsto. Prepričajte se, da ste ga pravilno navedli.
Težava je v tem, da bo zdaj, če bomo kodiranje stolpcev nastavili nazaj na UTF-8, MySQL znova zagnal kodiranje podatkov latin1 do UTF-8 in vrnili se bomo tam, kjer smo začeli. Da bi se temu izognili, se vrsta stolpca spremeni v blob in nato nastavi na UTF-8. To izkorišča dejstvo, da MySQL ne bo poskušal kodirati bloba. Tako lahko 'goljufamo' pretvorbo nabora znakov MySQL, da se izognemo težavi z dvojnim kodiranjem.
Primer:
|_+_|
(Kot smo že omenili, ponovno uporabite ustrezno vrsto polja za tabelo.)
Izbrišite vrstice z samo enobajtnimi znaki, ki pripadajo začasni tabeli:
Vstavite fiksne vrstice nazaj v prvotno tabelo (preden to storite, zaženite nekaj izbir v začasni tabeli, da preverite, ali je bila pravilno popravljena, samo kot previdnostni ukrep).
|_+_|
Še eno stvar, ki si jo je treba zapomniti in preveriti, je, da so datoteke izvorne kode, datoteke virov itd. Pravilno shranjene s kodiranjem podatkov UTF-8. V nasprotnem primeru z vsemi 'posebnimi' znaki v teh datotekah ne bo mogoče pravilno ravnati.
Na primer, v Netbeansu lahko z desno miškino tipko kliknete svoj projekt, izberete lastnosti in nato pod 'Viri' najdete možnost kodiranja podatkov (običajno je to privzeto UTF-8, vendar je bolje, da preverite).
Ali pa v beležnici Windows uporabite možnost »Shrani kot ...« v meniju Datoteke in izberite možnost kodiranja UTF-8 na dnu pogovornega okna. (Upoštevajte, da je možnost »Unicode«, ki jo ponuja Notepad, dejansko UTF-16 in to ni tisto, kar želite.)
Čeprav je lahko nekoliko dolgočasno, si lahko vzeti čas za pregled teh korakov za sistematično reševanje težav s kodiranjem podatkov MySQL in PHP UTF-8 prihranite veliko časa. Dolgoročno je tovrstni metodični pristop veliko boljši od običajne težnje po popravljanju sistema.
Upam, da ta priročnik poudarja pomen upoštevanja opredelitve nabora podatkov pri prvotni nastavitvi projektnega okolja in delu v programskem projektnem okolju, ki upošteva kodiranje znakov pri manipulaciji z besedilom in nizi.
Sorodno: Pred odpravljanjem napak PHP, ki ne deluje, preverite seznam 10 najpogostejših napak, ki jih naredijo razvijalci PHP (Pred odpravljanjem napak PHP, ki ne deluje, si oglejte ta seznam 10 najpogostejših napak, ki jih naredijo razvijalci PHP)