UTF-8, MySQL, kódování a PHP funkce pro práci s řetězci: strlen, substr aj.
Možná jste při práci s PHP narazili na problém s UTF-8 kódováním. Doposud jste využívali kódování cp1250 nebo iso-8859-2 a nebyl problém. Okolnosti vás přinutily požívat UTF-8 a najednou bum. Na stránkách se vám chybně vypisují znaky s českou diakritikou a nevíte co s tím.
Jak správně použít UTF-8 a MySQL?
Je třeba dodržet následující pravidla:
- Po připojení nastavit kódování, ve kterém bude probíhat komunikace s databázovým serverem:
mysql_query("SET NAMES 'utf8'"); nebo mysql_query('SET CHARACTER SET utf8'); Od PHP 5.2.3 a MySQL 5.0.7 raději použijte: mysql_set_charset('utf8'); Je to správná a bezpečná varianta pro použití mysql_real_escape_string(). Více: 1, 2, 3. - Kódování PHP souborů nastavit na UTF-8 (pozor na počáteční UTF-8 boom znak)
- Odesílat hlavičky s UTF-8 kódováním:
header('Content-Type: text/html; charset=utf-8'); - Nastavit UTF-8 kódování v HTML (meta tagy, xml hlavička aj.)
- Používat PHP řetězcové funkce, které zvládají UTF-8 (viz dále)
PHP funkce a podpora UTF-8
Všechno výše jste nastavili a teď chcete vypsat následující:
echo strlen('Zdeněk Večeřa');
Asi očekáváte “13″ (znaků), ale pravdu byste neměli. Vypíše se “16″. Důvod je, že funkce strlen() není “UTF-8 friendly”, a má tedy v tomto případě problém se znaky s diakritikou. Naštěstí existují alternativní funkce, které si poradí s mnoha kódovaními, vč. UTF-8. Ve jméně funkcí je prefix mb_, takže výše uvedený příklad by vypadal takto:
echo mb_strlen('Zdeněk Večeřa');
Když funkci provedete, vypíše se opět “16″. Kde je problém? Chybou je špatně nastavené kódování. Nastavíte ho takto:
echo mb_strlen('Zdeněk Večeřa', 'UTF-8');
Výše uvedený příklad už vypíše správně “13″.
Alternativy s prefixem na začátku existují pro všechny významné PHP funkce, které pracují s řetězci. Nevýhodou může být (nutnost) uvádět kódování.
Nastavení výchozího kódování pro mb_ funkce
PHP umožňuje nastavit výchozí kódování, které se použije pro všechny mb_ funkce:
mb_internal_encoding('UTF-8');
Zjistit aktuálně nastavené kódování můžete takto:
echo mb_internal_encoding();
Poté už lze bez problému použít:
echo mb_strlen('Zdeněk Večeřa');
UTF-8, preg_replace() a česká diakritika
Pokud v regulárních výrazech pracujete s českou diakritikou, je třeba přidat parametr u:
$search = 'šimáček';
$text = 'Dobrý den, přeji jen. Šimáček';
echo preg_replace('/(' . $search . ')/iu', '\\1', $text);
Výše uvedený kód zvýrazní slovo “Šimáček”:
Dobrý den, přeji jen. Šimáček.
Kdybychom nepoužili parametr u, slovo by se nezvýraznilo (kvůli odlišné velikosti prvního písmene š/Š).
September 1st, 2009 at 21:32
nebo proste pouzit iconv a nemusi se pracne prepisovat kilobajty a kilobajty kodu kvuli zameny funkci ;) Dobre zminit – http://cz2.php.net/manual/en/book.iconv.php
September 2nd, 2009 at 02:26
Nevím, jak vám, ale mně přijde jednodušší hromadně nahradit těch pár používaných funkcí za mb_ varianty, než pracně implementovat iconv (nehledě na výkon).
September 3rd, 2009 at 07:32
Díky za článek. Já mám potíže, když se snažím v PHP 5.2.9 zvýraznit výsledky vyhledávání textů v UTF8 takto:
1. $text = preg_replace(“~$search~i”, ‘\’, $text);
——-
ALE preg_replace není multibyte, má problémy s češtinou. Nenajde slova, která obsahují velká písmena s diakritikou, např. pokud text je “Šimáček” a hledá se “šimáček”. Když se hledá přesně, to znamená “Šimáček”, chytne se a označí.
2. $text = mb_eregi_replace($search, ”.$search.”,$text, “i”);
Chytne se vždy, ale převádí velikost písmen. Jestliže text je “Čermák” a hledá se “čermák”, výsledek je označené “čermák”. Pokud budu hledat “ČERMÁK”, výsledkem bude označené ČERMÁK.
Takže buď správná velikost písmen, ale nespolehlivé označování, nebo spolehlivé označování a zase špatná velikost písmen.
September 3rd, 2009 at 07:35
Vidím, že tagy byly vypáleny. Ještě jeden pokus s entitami:
1. $text = preg_replace(“~$search~i”, ‘<span class=”search-result”>\</span>’, $text);
2. $text = mb_eregi_replace($search, ‘<span class=”search-result”>’.$search.’</span>’,$text, “i”);
September 3rd, 2009 at 12:24
Díky .. moc mi to pomohlo – mal som problém, keď som nahrával údaje do databázy cez webové rozhranie čo som vytvoril, zobrazolvalo sa to OK, len v phpMyAdmin som videl divokú diakritiku.
Po pridaní “mysql_query(‘SET CHARACTER SET utf8′);” do class-u ktorým sa pripájam k db všetko fachá krásne ;-)
September 3rd, 2009 at 13:14
jarks:
Je třeba přidat parametr u:
$search = ‘šimáček’;
$text = ‘Dobrý den, přeji jen. Šimáček’;
echo $text = preg_replace(‘/(‘ . $search . ‘)/iu‘, ‘\\1‘, $text);
September 7th, 2009 at 08:54
Díky moc. Tenhle modifikátor mi úplně unikl.
(The PHP preg functions, which are based on PCRE, support Unicode when the /u option is appended to the regular expression.)
April 19th, 2010 at 15:26
Důvod je, že funkce strlen() není “UTF-8 friendly” —> To není úplně pravda, protože funkce strlen() vrací počet bytů řetězce a u některých znakových sad tedy i délku řetězce! Takže to číslo, které vrátí je dobře ;-)