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

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

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: 50 (nové: 0)

Diskuse

skybedy:

Nevzroste při použití UTF-8 nadměrně velikost souboru? Díky.

ikona Jakub Vrána OpenID:

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ší.

xXx:

rek bych ze vyroste

Ondra:

Nechtel bys nekdy vyjmenovat praci s utf? Mam na mysli nahrazovani, hledani atp.

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

ikona Jakub Vrána OpenID:

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

pif:

joooo mas pravdu... to je fakt :)))) to musim jeste zpravit :))

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.

ikona Jakub Vrána OpenID:

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

skybedy:

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

ikona Jakub Vrána OpenID:

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

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.

Chytrex:

Zkus se podívat po PHPeditorIDE.. Je to freeware a poporuje všechny možné kódování..

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.

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 ?

ikona Jakub Vrána OpenID:

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.

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?

ikona Jakub Vrána OpenID:

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%';

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

ikona Jakub Vrána OpenID:

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

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.

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.

ikona Jakub Vrána OpenID:

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.

David:

Díky moc, vyzkouším.

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

ikona Jakub Vrána OpenID:

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.

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

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

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

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.

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.

ikona Jakub Vrána OpenID:

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

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

ikona Jakub Vrána OpenID:

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.

Jakub:

Jako jednodušší použití vidím dát na začátek kódu
<?php
mb_internal_encoding
("UTF-8");
...
/*a pak použít namísto substr() mb_substr()*/
?>

viz:
http://www.php.net/manual/en/function.mb-internal-encoding.php
http://www.php.net/manual/en/function.mb-substr.php

Mě to zafungovalo perfektně...

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

Vlastimil Fišer:

Ahoj. Chtěl jsem se zeptat, beru data na stránku přes <? include("nazev_souboru.txt"); ?> a i když mám na webu (v hlavičce) nastavené UTF-8 kódování a v tomhle TXT souboru také (v PSPadu nastaveno v "Formát" -> "UTF-8") tak mi to nebere diakritiku a píše mi to místo toho otazníky. Nevíte jak bych to mohl vyřešit ?

Děkuji, Vlastimil Fišer

ikona Jakub Vrána OpenID:

Jak přesně se nastavuje to kódování? Je vkládaný soubor určitě ve správném kódování?

Mimochodem, proč vůbec textový soubor vkládáš pomocí include?

Vlastimil Fišer:

Děkuji za rychlou reakci.
Formát volím tak, že v PSPadu, nahoře v liště, kliknu na "Formát" a poté zaškrtnu "UTF-8". Zkoušel jsem zaškrtnout i jiné, ale vůbec to nemá vliv nějak, vždy sou tam stejné otazníky a při změně na jiný formát (jakýkoliv) to je pořád stejné. V hlavičce webu mám kódování správně na 100%.

Vkládám ho tam přes include, jelikož to mám do Wordpress šablony kterou jsem vytvořil, ale bohužel dělá mi neplechu když to ukládám přes editor (při opětovné editaci mi to modifikuje kód, podle toho editoru ve WP).

Už si nevím rady. :(

Vlastimil Fišer:

Tak už jsem to udělal. Stačilo to neukládat do TXT ale do PHP souboru (i když v kódu PHP nemám, myslel jsem si že je to zbytečné). Teď bych se jen chtěl zeptat, zdali nevíte, jak bych mohl udělat to, aby vyhledávače neindexovali ty PHP soubory ze kterých to "tahám".

Děkuji, Vlasta

Recepty:

Tak s tou PHP hlavickou som sa trapil, lebo mi tiez nefunguje to kodovanie, tak dakujem za tip idem to vyskusat a prerobit.

Jan Návrat:

Uctivě zdravím a prosím o radu =)

Potřebuji vypisovat řetězce s pevným počtem znaků. Tj např potřebuji aby proměná $out měla při výpise vždy přesně 10 znaků. Co vím, měly by k tomu být určeny funkce řady printf, ale bohužel mi nefungují při použití UTF-8.

$jmeno="Žok";
$out = sprintf("%-10s", $jmeno);

Proměná $out po provedení této části kódu obsahuje řetězec jen s 9 znaky a né 10 (znak Ž sežere dvě místa).

Poradíte prosím jak na to? Moc děkuji =)

ikona Jakub Vrána OpenID:

Obávám se, že si to budeš muset napsat sám. Ani v http://www.php.net/manual/en/book.mbstring.php jsem to nenašel. Na co to potřebuješ?

Jirka:

Vkládám php menu do stránky. V souboru menu mám pouze <table>...</table>. Jak mám nastavit kódování stránky, aby se mi háčky a čárky zobrazovaly všude správně? Když zvolím jedno, zobrazuje se blbě obsah menu, když druhé, zobrazí se blbě zbytek stránky.
Děkuji

Michal:

Rada je jednoduchá a to sjednotit kódování.

Tomáš Balíček:

Dobrý den,

prosím o radu. Z banky vytahuji data pomocí skriptu a kódování v bance je ISO-8859-2 ale potřebuji vložit data do databáze, kde je použité kódování UTF-8 ale bohužel se mi nedaří převést kódování. Zkoušel jsem následující metodu:

$jmeno2 = mb_convert_encoding($jmeno, 'UTF-8', 'ISO-8859-2' );

//$jmeno = TOMÁŠŠ BALÍČEK
//$jmeno2 = TOMà Š BALĂ ÄŒEK //v zobrazení ISO-8859-2
//$jmeno2 = TOMÁ  BALÍČEK //v zobrazení UTF-8

Předem děkuji za odpověď opradu jsem už vyzkoušel všechno možné a nic mě nenapadá.

Tomáš Balíček

Katka:

Tento soubor .php jsem includovala do jineho souboru....porad to pise kosoctverce s otazniky misto hacek a carek, co s tim???

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Trendymat</title>
</head>

<h2>Vítejte</h2>
<body>
Tato stránka je zaměřena <br />
</body>
</html>

ikona Jakub Vrána OpenID:

Kódování je potřeba nastavit také v PHP, např. tímto kódem umístěným na začátek souboru:

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

ikona Jiří:

Dobrý den,
na celých webovkách se mi špatně zobrazuje čeština, v menu prohlížeče si musím nastavit znakovou sadu Středoevropský Windows. Přitom v hlavičce webu to mám definováno. Poraďte prosím jak to zpravit.

Hynek:

Importuji data ze starého excelu (s příponou xls) a potřebuji je překódovat (php mám v utf-8). Jak to udělám?

Vložit komentář

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:

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.