Práce s UTF-8

Školení, která pořádám

Kódování UTF-8 se od většiny ostatních kódování liší tím, že znaky ukládá do proměnlivého počtu bajtů – spodní polovinu ASCII tabulky do jednoho bajtu, např. česká písmena s diakritikou do dvou bajtů a např. čínské znaky do tří nebo čtyř bajtů. Kvůli tomu pochopitelně nefungují běžné funkce, které pracují s pozicí v řetězci (např. substr) ani je nelze snadno upravit jako např. v případě dvoubajtového kódování UCS-2. Náhradu pro základní funkce poskytuje knihovna iconv (např. iconv_substr), která je v PHP 5 k dispozici už v základní výbavě. Pokročilejší funkce nabízí knihovna MBString, navíc s možností namapovat je direktivou mbstring.func_overload na běžné funkce.

<?php
iconv_set_encoding("internal_encoding", "UTF-8");

if (iconv_strlen($_POST["jmeno"]) < 3) {
    echo "Jméno musí mít alespoň tři znaky.\n";
}
?>

Pro převod kódování se dají použít obě, rozšíření Recode se naopak doporučuji vyhnout, protože za převedené řetězce za určitých okolností přidává nesmyslné znaky.

Podporu kódování UTF-8 mají i Perlovské funkce pro práci s regulárními výrazy, stačí použít modifikátor u. Regulární výrazy potom budou pracovat místo s bajty se znaky v kódování UTF-8.

<?php
if (!preg_match('~.{3,} [0-9]+~u', $_POST["adresa"])) {
    echo "Adresa musí mít alespoň tři znaky a číslo domu.\n";
}
?>

Při vytváření skriptů je potřeba dávat pozor ještě na jednu věc – některé editory uvozují soubor v kódování UTF-8 posloupností bajtů, která vyznačuje pořadí bajtů v Unicode souborech. Pro PHP interpret to je ale výstup jako každý jiný, takže u takto uvozených dokumentů nelze používat např. funkci header nebo setcookie. Obejít se to dá zapnutím direktivy output_buffering, vyřešit potom vytvářením souborů bez těchto prvotních znaků (např. ve SciTE tomu odpovídá kódování UTF-8 Cookie).

Jakub Vrána, Výuka, 5.9.2005, diskuse: 19 (nové: 0)

Diskuse

Arcao:

mozna by ty tidici znaky (BOM) neskodilo trochu vysvetlit. Treba tu: http://www.sweb.cz/pichlik/archive/2003_08_…#106189779983242403

ikona Jakub Vrána OpenID:

Obzvláště je vhodné si na té stránce přečíst update, protože informace o endianech jsou v zásadě správně, ale spojení s UTF-8 je zcela mylné.

Lukoko:

Jen doplním, že sekvenci bytu na začátku UTF-8 dokumentu se říká BOM.

ikona Radek Hulán:

"Náhradu pro základní funkce poskytuje knihovna iconv (např. iconv_substr), která je v PHP 5 k dispozici už v základní výbavě" - toto platí samozřejmě jen po Windows, nad Linuxem je potřeba ji manuálně stáýhnout a zkompilovat, není součástí zdrojáků PHP 5

halogan:

Dovolim si odkazat na reseni dvou castych problemu:
http://halogan.xblog.cz/archiv/2005/08/php…-prace-s-utf-8

ikona spaze:

UTF-8 BOM by snad melo resit --enable-zend-multibyte pri ./configure, ale popravde, jeste jsem se nedostal k overeni/vyvraceni.

ikona spaze:

tak potvrzuji --enable-zend-multibyte resi UTF-8 BOM: http://forum.builder.cz/read.php?157,1268791,1269596#msg-1269596

Garf:

Mám k UTF-8 jeden dotaz: jak lze rozumně upravovat stránky/skripty pokud jsou napsané v kódování UTF-8? Kromě editoru, kde můžu zvolit znakovou sadu souboru i v jakém formátu se děje úprava, jsem zatím narazil vždy na problém, že otevřu-li skript/stránku napsanou v UTF-8 např. v notepadu, pak vidím jen rozsypaný čaj, protože notepad používá znakvou sadu windows, tedy 1250. Jak to lze obejít? Pokud nějak? Asi neexistuje něco takového, jako UTF-8 jako "systémová sada"... (pokud je to hloupý dotaz, omlouvám se - nedávno jsem na ten problém narazil, když jsem se rozhodl předělat vše na UTF-8, a nepodařilo se mi jej vyřešit)

Štěpán Svoboda:

Ahoj Jakube,

teď jsem narazil na zajímavý problém. Nevím, zdali ho mám vložit do nějakého systému hlášení chyb v PHP.

Zdá se, že funkce iconv_strlen() nepracuje s řetězci kratšími než 3 znaky. Přijde mi to podivné chování. Ještě to jdu zkoumat.

Štěpán Svoboda:

např.
<?php

$s
= "žu";
echo
$iconv_strlen($s, 'UTF-8');
// Unkown Error 20

$s = "žuk";
echo
$iconv_strlen($s, 'UTF-8');
// 3
?>

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: Štěpán Svoboda

ikona Jakub Vrána OpenID:

Také jsem si tohoto problému všiml, doporučuji vytvořit bug report na http://bugs.php.net.

ikona dgx:

možná tu bude souvislost: http://bugs.php.net/?id=37773

Crempa:

Ahoj,
může mě prosím někdo vysvětlit přesnou funkci přepínače "u" u perl comp. regular funkci?
Z dokumentace jsem pochopil, že je při jeho použití brán text v šabloně jako by byl kódován v utf-8, znamená to teda že pokud bude celej soubor scriptu kódován v utf-8, tak je tenhle přepínač zbytečnej? Nebo je to všechno jinak :-) ?

Díky

PS: zajimave pocteni na tema UTF-8 v PHP, treba se to nekomu bude hodit http://www.phpwact.org/php/i18n/utf-8

ikona Jakub Vrána OpenID:

Naopak – když je skript v kódování UTF-8, mohu přepínač bez obav použít a získat tak funkčnost, kterou zajišťuje.

Crempa:

aha, diky
popravde ale stejne nemuzu najit situaci ve ktere by to bez prepinace pracovalo jinak nez s prepinacem, i v clanku uvedeny priklad funguje myslim spravne i bez pouziti prepinace

ikona Jakub Vrána OpenID:

Např. řetězec "ěš" má v UTF-8 čtyři bajty, i když to jsou jenom dva znaky. Takže bez přepínače /u by to vzalo i kratší adresy.

Crempa:

ahaa, tak uz je to jasne, diky moc za nakopnuti

Vladka:

Dobrý deň, vedeli by ste mi niekto pomôcť pri dekódovaní textu ﭺﭡﭲﭡﭧﭯﭺﭡ lebo viem si jednotlivé znaky previesť do UTF-8 no neviem, či je možné z toho dosťať text, poprípade ako....vopred ďakujem každému za pomoc...

Al Arabbia:

Vladka to čo s tým vieš urobiť ti úplne stačí na "tvoj" problém :)
avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.