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 š/Š).




9 Responses to “UTF-8, MySQL, kódování a PHP funkce pro práci s řetězci: strlen, substr aj.”

  • Lukyer Says:

    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

  • Zdeněk Veřeřa Says:

    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).

  • jarks Says:

    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.

  • jarks Says:

    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”);

  • Kuko Says:

    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 ;-)

  • Zdeněk Veřeřa Says:

    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);

  • jarks Says:

    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.)

  • Jan Kahoun Says:

    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 ;-)

  • dotaz Says:

    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