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:

  1. 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.
  2. Kódování PHP souborů nastavit na UTF-8 (pozor na počáteční UTF-8 boom znak)
  3. Odesílat hlavičky s UTF-8 kódováním:
    header('Content-Type: text/html; charset=utf-8');
  4. Nastavit UTF-8 kódování v HTML (meta tagy, xml hlavička aj.)
  5. 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 š/Š).



Comments ( 9 )

  1. Lukyer
    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
  2. Zdeněk Veřeřa
    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).
  3. jarks
    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.
  4. jarks
    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");
  5. Kuko
    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 ;-)
  6. Zdeněk Veřeřa
    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);
  7. jarks
    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.)
  8. Jan Kahoun
    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 ;-)
  9. dotaz
    nevíte někdo co mám udělat u quick cms když mi po objednávce přijde email a sou tam místo diakritiky znaky

Leave a reply

Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>