Výběr kódování znaků

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

Dopsal jsem knihu

Při vytváření českých (nebo jiných ne-ryze anglických) stránek je potřeba vybrat, jaké kódování znaků se bude používat. Pro češtinu se používají hlavně tyto tři:

Windows-1250 se používá hlavně na Windows, ISO-8859-2 na Unixu, UTF-8 je univerzální kódování, pomocí kterého lze zapsat v podstatě libovolný znak používaný kdekoliv na světě. Naštěstí už jsou pryč doby, kdy prohlížeče dokázaly zobrazit pouze kódování odpovídající operačnímu systému, pod kterým běží, takže není nutné vytvářet skripty, které kódování automaticky převádí, a obvykle stačí kódování prohlížeči pouze vhodně oznámit:

<?php
header("Content-Type: text/html; charset=windows-1250");
?>

K dispozici je také direktiva default_charset. Připomínám, že kvůli případnému uložení stránky na disk je také vhodné stejnou hodnotu uvést i ve značce <meta http-equiv="Content-Type">. Pokud ale HTTP hlavička poslaná PHP obsahuje jinou hodnotu, tak dostane přednost, takže značka <meta http-equiv="Content-Type"> sama o sobě nestačí.

Které kódování vybrat? Doporučit mohu jednoznačně UTF-8, které má tu hlavní výhodu, že není specifické pro češtinu (nebo pro střední Evropu) a lze v něm tedy zapsat libovolné znaky. Podpora v prohlížečích a editorech je také dobrá. Pokud vytváříte stránky v XHTML a nechcete uvádět XML deklaraci (kvůli problémům s tím spojeným) a zároveň zůstat v souladu s normou, je to také vaše jediná možnost.

UTF-8 je na rozdíl od Windows-1250 nebo ISO-8859-2 vícebajtové kódování – pro uložení jednoho znaku se může použít více bajtů. Znaky ze spodní poloviny ASCII tabulky jsou uloženy do jednoho bajtu, ostatní znaky potom do dvou až čtyř bajtů. Z toho plynou i některé problémy – např. funkce strlen vrací počet bajtů, nikoliv znaků. Pokud chcete vrátit počet znaků, můžete jako náhradu použít funkci iconv_strlen, která použité kódování zohledňuje. Podobný problém na nás číhá i v MySQL – varchar(40) vyhradí v MySQL až do verze 4.0 místo na 40 bajtů, nikoliv znaků. Ke změně došlo až v MySQL 4.1 (stabilní verze od října 2004), kde je práce s kódováními podstatně vylepšena (používané kódování lze nastavit pro server, databázi, tabulku i sloupec, ve starších verzích to šlo pouze pro server) a UTF-8 se používá i interně např. pro ukládání názvů sloupců.

Neaktuální verze MySQL je i důvod, proč je tento blog publikován ve Windows-1250 a ne v UTF-8. Pokud by se někdo pokusil např. do padesátibajtového sloupce vložit padesátiznakový UTF-8 řetězec s diakritikou (nebo i o něco kratší s hodně speciálními znaky), tak se tento řetězec pochopitelně ořízne. Pokud by se navíc ořízl uprostřed bajtů tvořících jeden znak, mohl by při výstupu dokonce způsobit nevaliditu dokumentu.

Jakub Vrána, Seznámení s oblastí, 11.3.2005, diskuse: 35 (nové: 0)

Diskuse

skybedy:

Nevzroste při použití UTF-8 nadměrně velikost souboru? Díky.
# 11.3.2005 11:48:27 reagovat

ikona Jakub Vrána:

Vzroste jen málo, protože více bajtů se používá jen pro ukládání speciálních znaků (pro české znaky s diakritikou vždy dva). Znaky z dolní poloviny ASCII tabulky (a tedy i všechny operátory a např. číslice) zaberou pouze jeden bajt. Např. tato stránka má v jednobajtovém kódování 7820 bajtů, v UTF-8 8146 bajtů, to je nárůst 4%. Při použití komprese by byl nárůst ještě menší.
# 11.3.2005 11:57:43 reagovat

xXx:

rek bych ze vyroste
# 12.7.2006 17:29:03 reagovat

Ondra:

Nechtel bys nekdy vyjmenovat praci s utf? Mam na mysli nahrazovani, hledani atp.
# 11.3.2005 13:16:05 reagovat

pif:

na mem blogu bezi vse v utf8. A i na stare databazi. Na mem blogu v tom nevidim problem, protoze do problematickych mist php + mysql + utf8 nemusel vstupovat :)
# 11.3.2005 14:57:50 reagovat

ikona Jakub Vrána:

Viz např. stále nevyřešená diakritika u jména autora diskusního příspěvku na tvém blogu :-).
# 11.3.2005 15:01:01 reagovat

pif:

joooo mas pravdu... to je fakt :)))) to musim jeste zpravit :))
# 11.3.2005 18:56:40 reagovat

timqui:

ohledne kodovani jsem narazil na jednu zajimavou vec u funkce urlencode()

funkce vrati vzdy prekodovane znaky v kodovani, ve kterem je napsan skript. A to ikdyz pred tim dany retezez rucne prekoduji do pozadovaneho kodovani (treba autoczech).

delo se mi to ve skriptu v UTF a volal jsem pomoci file() stranku (vyhledavace), ktera byla ve win-1250. tedy potreboval jsem do adresy pridat retezec (klicove slovo) we win-1250.

jako reseni me napadolo urlencodovany retezec prepsat pomoci str_replace.
# 11.3.2005 15:54:26 reagovat

ikona Jakub Vrána:

"urlencode() vrati vzdy prekodovane znaky v kodovani, ve kterem je napsan skript" - to není pravda. urlencode() pracuje podobně jako většina ostatních funkcí s bajty. Pokud mám skript v UTF-8 a chci parametr předat ve Windows-1250, lze použít:
<?php
$q
= urlencode(iconv("UTF-8", "Windows-1250", $q));
?>
# 11.3.2005 16:03:14 reagovat

skybedy:

Jaký používáte editor, když chcete mít kódování v ISO, popřípadě v UTF ? Díky.
# 15.3.2005 13:10:56 reagovat

ikona Jakub Vrána:

Používám SciTE http://www.scintilla.org/SciTE.html, které podporuje UTF-8 a kódování OS (na Windows tedy Windows-1250, na Linuxu ISO-8859-2).
# 15.3.2005 13:13:20 reagovat

skybedy:

Já právě teď dva dny stahuju všecko možné, je spousta hezkých editorů, jsou i freeware, ale prostě naše ISO nepodporují.
Jmenovaný SciTE jsem měl také, ale moc se mi nezdál, zkusím ho asi teda stáhnout znovu.
# 15.3.2005 13:41:06 reagovat

Chytrex:

Zkus se podívat po PHPeditorIDE.. Je to freeware a poporuje všechny možné kódování..
# 28.1.2006 14:55:31 reagovat

skybedy:

Teď jsem přišel na jednu nemilou věc v souvislosti s UTF-8.
IE neumí při tomto k´dování použít font MS Serif, který rád používám, a který by měl být jinak všeobecně kompatibilní.
Při Iso i Winndows to normálně jede.
# 31.3.2005 11:57:48 reagovat

abtris:

Ja jsem se dostal prechodem na utf-8 do jinych problemu:
1) zacala se obevovat chybova hlaska:Warning: Cannot modify header information - headers already sent by ...
Pri kodovani iso se to nedeje.
2) dalsi problem mam pri pouziti include('neco.php') kde mam nejaky text, tak to nadela problemy jen v IE.
Problem spociva v prvnich 3 znacich co se podle nich utf-8 rozpoznava, prijde mi ze tam neco zustane co by nemelo, dela mi to apache pod linuxem (1) a to druhe je problem IE (2) v Opere a Mozille/FF to neni problem.

Ma nekdo nejakou radu jak z toho uspesne ven a zustat u UTF-8 ?
# 25.6.2005 17:54:57 reagovat

ikona Jakub Vrána:

Té trojici znaků se říká BOM (http://en.wikipedia.org/wiki/Byte_Order_Mark) a vzhledem k tomu, že má jenom informativní charakter, je vhodné její doplňování v textovém editoru vypnout. Třeba ve SciTE se to dělá nastavením kódování na UTF-8 Cookie.

Není to problém Apache, PHP ani IE.
# 26.6.2005 17:16:38 reagovat

UTF a české znaky:

Nazdar,
také zkouším přejít z cp1250 na utf-8, ale narazil jsem na potíž v podobě znaků Ď a Č - ani doma, ani na vlastnim serveru, ani na hostingu (Banan.cz) se MySQL (verze 4.1) nechová korektně a místo těchto dvou znaků (malá i velká písmena) vyhodí dvoubajtový nesmysl. Jiná česká písmena, třeba Ř, jsou v pohodě, problém je jen s těmito dvěma. Nějaká elementární chyba je snad vyloučena, všechny ostatní české znaky jsou bez problémů.
Nesetkali jste se s tím už někdo?

# 24.12.2005 18:52:32 reagovat

ikona Jakub Vrána:

S tímto konkrétně jsem se nesetkal, k přečtení doporučuji leda http://php.vrana.cz/mysql-4-1-kodovani.php a ověření SHOW VARIABLES LIKE 'collation%';
# 25.12.2005 10:59:22 reagovat

Jarda Antoš:

Jen upozorňuji, že problém s počtem bitů je s UTF-8 i u serializace. Chvíli mi trvalo než jsem přišel na to, že tím pádem serialize nejde použít. Použil jsem na text před serializací base64 a obešel to... no snad napadne někoho něco lepšího :o)

Zdarec Jarda
# 10.4.2006 12:14:42 reagovat

ikona Jakub Vrána:

V jakém případě nejde serialize() použít? PHP s řetězci pracuje jako s posloupností bajtů a použité kódování by mu tedy mělo být zcela lhostejné.
# 10.4.2006 12:36:23 reagovat

Andrew:

Musím jen potvrdit, že při serialize pole v utf-8 dojde k chybě. Řeší se to i v diskusi na php.net pod zmíněnými funkcemi.
# 12.10.2007 20:22:28 reagovat

David:

PHP neumím, jenom používám e-mailový formulář (metoda post) a na seznam.cz mi ze serveru chodí špatné kódování: znaky jako ř, č apod. to dokonce bez náhrady vymaže. Dá se to nějak řešit? Používám skript z http://tvorba-webu.zdarek.com/php/email.php. Díky.
# 3.1.2007 23:08:09 reagovat

ikona Jakub Vrána:

Skript je velice primitivní. Aby fungovala čeština, měl by posílat nějaké hlavičky a kódovat alespoň předmět. Viz http://php.vrana.cz/e-mailovy-formular.php a http://php.vrana.cz/kodovani-hlavicek-e-mailu.php.
# 4.1.2007 11:12:52 reagovat

David:

Díky moc, vyzkouším.
# 22.1.2007 17:57:47 reagovat

Zajo:

Pracujem na jednom serveri, kde nie je nainstalovany mysqlAdmin, cize sa v tom pracuje velmi zle a vsetko musim davat cez priamy mysql query . aj tabulky som tak musel nahravat :(

Ale mam iny problem. Nahral som tam vsetko s kodovanim UTF8 a zoradenim utf8_slovak_ci. problem je  v tom, ze mi neberie slovensky znak ť(makke t) a namiesto neho pise otazniky. Dalo by sa to nejako vyriesiet? Dakujem vopred
# 30.10.2007 22:27:22 reagovat

ikona Jakub Vrána:

K prvnímu problému: zkus http://phpminadmin.sf.net.

Druhá věc: ověř, jestli jsou databáze a tabulky skutečně ve správném kódování (třeba v phpMinAdmin) a jestli po výběru databáze voláš SET CHARACTER SET.
# 31.10.2007 10:02:31 reagovat

Zajo:

Pomocou klasickych metod som to nevyriesil .. :(

Ale podarilo sa mi to inak cez str_replace som si pred ulozenim do DB ten znak premenil na kombinaciu inych znakov(napriklad ===) a tie som pri zobrazeni premenil s5. Jednoduche, ale inak som to nevedel vyriesit. Aj tak dakujem za rychlu odpoved :)
# 3.11.2007 18:53:19 reagovat

Vojta:

Mám problém s kódováním stránky, nejsem žádný profík a moc se v tom nevyznám, ale v mysql se mi podařilo nastavit české znaky, a když se na moje texty podívám v databázi tak tam všechny české znaky jsou, ale když si to zavolám na stránku pomoci Mysql_Query.... tak mi to vypíše ten text s otaznikama místo českých znaků.

Co s tím??(pokud by byl nekdo ochotny mi poradit muzete mi i napsat na mail: vojta.belovsky@seznam.cz) předem dík
# 8.3.2008 12:12:09 reagovat

Megaloman:

Zkus hned po připojení a výběru databáze oznámit klientovi, s jakou znakovou sadou chceš pracovat: "SET NAMES ..."

Ale pokud jsi české znaky nastavil až nad vytvořenými daty, tak ti nepomůže nic, snad jen vymazat a vložit znova (nejlépe přes php).
# 12.3.2008 12:56:00 reagovat

pethon:

Při php výpisu z databáze jsem nemohl dosáhnout korektního zobrazení češtiny utf8, nepomohlo ani nastaveni "set names..." etc. Po dotazu SHOW VARIABLES LIKE 'collation%'; jsem zjistil, že chyba bude nejspíš v odlišném nastavení kódování server_collation, takže: pokud máte podobný problém zkuste: http://czropa.wz.cz/?src=doc/javamysql.php
Řešením bylo nastavit v "my.ini" default-character-set=utf8.
# 28.4.2008 01:38:00 reagovat

Rataja:

Chci ořezat řetězec na několik znaků, řekněme zkrátit, ale když se trefím tak, že poslední písmeno je diakritikou, tak se toto písmeno nezobrazuje korektně. Po přečtení příspěvků chápu, že je to tím, že je tento znak rozdělen na vice bytu. Jakym zpusobem pohlidat, spravne zobrazeni posledniho znaku?

$string = vepřové;
echo substr($string, 0, 4);

Diky moc za radu

R.
# 2.8.2009 22:34:19 reagovat

ikona Jakub Vrána:

Musíš použít funkci, která kódování respektuje, např. iconv_substr(). Dá se použít i taková finta, která nevyžaduje žádnou externí knihovnu: <?php preg_replace("~(.{0,$length}).*~su", '\\1', $string); ?>.
# 3.8.2009 11:04:09 reagovat

Rataja:

Co musím přečíst a nastudovat, abych byl stejný machr? Díky moc, fce zabrala a já dostávám výsledky, které potřebuji.

Opravdu děkuju
# 3.8.2009 19:49:23 reagovat

ikona Jakub Vrána:

Co se funkcí týče, tak studentům radím přečíst si jednořádkové popisy vestavěných PHP funkcí. Člověk tak získá přehled o tom, co PHP dokáže, takže pak když něco potřebuje udělat, tak ví, že to jde. A najít jak už obvykle nebývá velký problém. Začít můžeš na http://www.php.net/manual/en/extensions.membership.php.
# 4.8.2009 09:55:12 reagovat

ikona Honza:

Dobrý den, začal jsem se zabývat redakčním systémem, alemé znalosti PHP jsou takřka nulové. Jde o zásahy do přednastavených nadpisů sekcí atp... Používám Joomlu 1.5. Zatím mi běží na lokálním serveru a testuji možnosti.
..............................zpět k problému:
Jde o zásahy do přednastavených nadpisů sekcí atp.
Kódování používám UTF-8 a všechen obsah se v češtině vypisuje správně (česká diakritika) ovšem pokud zasáhnu do PHP kódu a změním např. Modul registration form vypíše místo českých znaků prohlížeč typické znaky pro UTF-8 bez českých znaků. Moduly jsou programovány v angličtině, ale nevím zda je to tím. Pomůže mi někdo?
Podotýkám, že nejsem programátor, nicméně mne tato problematika velmi zajímá.
.....................Ukázka......................
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-gb" lang="en-gb" >
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
.................SPÍŠ JDE O TO ZDA STAČÍ ZMĚNIT PARAMETR "XML LANG"................................

...........UKÁZKA SKRIPTU VYPISUJÍCÍHO FORM..............
<?php else : ?>
<?php
if(JPluginHelper::isEnabled('authentication', 'openid')) :
       
$lang->load( 'plg_authentication_openid', JPATH_ADMINISTRATOR );
       
$langScript =     'var JLanguage = {};'.
                       
' JLanguage.WHAT_IS_OPENID = \''.JText::_( 'WHAT_IS_OPENID' ).'\';'.
                       
' JLanguage.LOGIN_WITH_OPENID = \''.JText::_( 'LOGIN_WITH_OPENID' ).'\';'.
                       
' JLanguage.NORMAL_LOGIN = \''.JText::_( 'NORMAL_LOGIN' ).'\';'.
                       
' var modlogin = 1;';
       
$document = &JFactory::getDocument();
       
$document->addScriptDeclaration( $langScript );
       
JHTML::_('script', 'openid.js');
endif;
?>
<form action="<?php echo JRoute::_( 'index.php', true, $params->get('usesecure')); ?>" method="post" name="login" id="form-login" >
    <?php echo $params->get('pretext'); ?>
    <fieldset class="input">
    <p id="form-login-username">
        <label for="modlgn_username"><?php echo JText::_('Username') ?></label><br />
        <input id="modlgn_username" type="text" name="username" class="inputbox" alt="username" size="18" />
    </p>
    <p id="form-login-password">
        <label for="modlgn_passwd"><?php echo JText::_('Password') ?></label><br />
        <input id="modlgn_passwd" type="password" name="passwd" class="inputbox" size="18" alt="password" />
    </p>
    <?php if(JPluginHelper::isEnabled('system', 'remember')) : ?>
    <p id="form-login-remember">
        <label for="modlgn_remember"><?php echo JText::_('Remember me') ?></label>
        <input id="modlgn_remember" type="checkbox" name="remember" class="inputbox" value="yes" alt="Remember Me" />
    </p>
    <?php endif; ?>
    <input type="submit" name="Submit" class="button" value="<?php echo JText::_('LOGIN') ?>" />
    </fieldset>
    <ul>
        <li>
            <a href="<?php echo JRoute::_( 'index.php?option=com_user&view=reset' ); ?>">
            <?php echo JText::_('FORGOT_YOUR_PASSWORD'); ?></a>
        </li>
        <li>
......................KONEC KÓDU......................
Pokud přepíšu do češtiny submit button a další, vyhodí to klasický ASCII znak pro nerozpoznaný znak "kosočtverec s otazníkem"............Díky
# 12.10.2009 09:10:39 reagovat

Vložit příspěvek

Používejte diakritiku. Nelze používat HTML značky, 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:

© 2005-2010 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.