Ékezetes FAQ webművészek számára (Nem mennek az ékezetek a szájtomon!)

K: Nem mennek az ékezetek a szájtomon, pedig már összevissza kapkodtam, mindent átállítottam és vissza, mit csináljak még?!
V: Végső esetben próbálj meg tájékozódni, valamilyen kódkészletet kiválasztani, és minden beállításnál azt használni.

K: Mi az a 'minden beállítás'?
V: Először jöjjön a HTTP-header, azon belül is a Content-Type, pédául ennek az oldalnak az esetében:
Content-Type: text/html; charset=UTF-8
K: Na ez honnan jön?
V: Statikus fájlok (HTML, CSS, JS stb) esetén a .htaccess-ben az AddDefaultCharset-ből (ha az nincs, akkor az apache globális beállítása érvényesül), dinamikus fájlok esetén ezt felülbírálhatjuk úgy, ha magunk állítjuk elő ezt a fejrész sort. Példa PHP-ban:
header ('Content-Type: text/html; charset=iso-8859-2');
Példa Perl CGI-ben:
print "Content-Type: text/html; charset=windows-1250\r\n";
K: PHP-ben mi lesz az alapértelmezés, ha nem használok header-t?
V: A php.ini-ből veszi az alapértelmezett értéket, pl:
default_mimetype = "text/html"
default_charset = "iso-8859-2"
K: Kipróbáltam, de nem ment!
V: Minden más kiíratás előtt kell lennie; PHP-ben az is gondot okoz, ha a <?php tag nem a fájl legelején van, hanem van előtte egy üres sor, szóköz, tabulátor, BOM; CGI esetén pedig az okozhatja a gondot, ha elfelejted a fejrészt lezáró üres sort kiadni, hiszen ekkor azt hiszi az Apache, hogy ez is az adathoz tartozik.
K: Mi az a BOM?!
V: Egy hárombájtos szekvencia a fájl elején, ami azt jelezné, hogy a fájl UTF-8 kódolású. Tudnod kell róla, hogy UNIX-ban nem használatos, csak Windows-ban; továbbá, hogy HTML, PHP, CGI stb. fájlban nincs rá szükség, szabadulj meg tőle! Bővebben itt: wiki:BOM
K: Szóval ilyenkor ne legyen BOM a fájl elején. Van olyan eset, amikor viszont érdemes BOM-ot használni?
V: Ha a programodból (PHP, CGI) olyan UTF-8 kódolású szöveges fájlt állítasz elő (pl .TXT, .CVS), amelyet a felhasználó külső programmal nyit meg (Notepad, Excel), akkor ezzel jelezheted az UTF-8 kódolást. PHP példa:
print "\xEF\xBB\xBF";

K: És hogyan lehet a HTTP-fejrészt ellenőrizni?
V: Például a wget -S opciójával, vagy a Firefox LiveHttpHeaders kiegészítőjével.

K: Nem veszi figyelembe a .htaccess-t, mit csináljak?
V: Lehet, hogy nem Apache-t használnak, hanem valamilyen egzotikus webszervert, amelyik nem ismeri ezt az opciót, vagy átnevezték a .htaccess-t (AccessFileName opció), vagy pedig a globális beállításban megtiltották, hogy a .htaccess-ből vegye ezt az opciót. Mindezen esetekben a szolgáltatóval kell egyeztetned, a legutóbbi esetben például ezt kell magadniuk:
AllowOverride FileInfo
K: Mi legyen a következő lépés?
V: A HTML fejrészben (HEAD) is meg lehet adni (értsd: érdemes megadni) a kódolást, valahogy így:
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-2">

K: De minek, ha ennek nincs prioritása a HTTP-fejrész fölött?
V: Valóban nincs, de a HTTP-fejrésszel szemben ez akkor is megmarad, ha az oldalt elmented fájlba, és később megtekinted/módosítod.

K: Ennek van értelme, de mi a helyzet a JS, CSS stb. fájlokkal?
V: Javascript-re nem tudom a választ, CSS esetén a @charset használható:
@charset "ISO-8859-2";
XML esetén a fejrész tartalmazza a kódkészletet, pl.:
<?xml version="1.0" encoding="iso-8859-2"?>
K: Magában a HTML-ben is meg lehet adni a kívülről beemelt javascript vagy stíluslap kódolását?
V: Hát például így:
<SCRIPT src="neve.js" type="text/javascript" charset="UTF-8">
<LINK href="neve.css" rel="stylesheet" type="text/css" charset="UTF-8">
Sőt, adott esetben az <A> tagban is megadhatjuk a linkelt oldal kódolását:
<A src="neve.txt" type="text/plain" charset="windows-1250">
K: Mi történik, ha az URL 'path' részében van ékezetes betű?
V: A HTTP-üzenetben %-szekvenciaként fog közlekedni az illető karakter kódja, de persze az nem garantált, hogy a szerver és a kliens ugyanazt a kódolást használják. Például a magyar wikipedia az utf8-at peferálja, de a latin2-t is elfogadja (illetve átirányítással kezeli)
kérés:
GET /wiki/R%E9pa HTTP/1.1

válasz:
HTTP/1.1 301 Moved Permanently
Location: https://hu.wikipedia.org/wiki/R%C3%A9pa

kérés:
GET /wiki/R%C3%A9pa HTTP/1.1

válasz:
HTTP/1.1 200 OK
K: És ha a 'domain' részben van ékezet, mint például http://szűrőgép.hu/?
V: A printable unicode avagy punycode nevű kódolást kell alkalmazni, és az xn-- prefixet tenni elé. Példa (az idn segédprogramot használva):
$ idn szűrőgép.hu
xn--szrgp-esa04e4h.hu
Lásd még az RFC3490-et és a libidn könyvtárat.
K: Tehát ha a 'domain' részben van ékezet, akkor szép magyaros szöveget láthatnak a felhasználók a címsorban? Tök jó!
V: Csak amíg ki nem javítják a böngészőket, ugyanis ez átverős oldalak készítésére is alkalmas (lenne). Lásd ezeket:
Wordfence: Chrome and Firefox Phishing Attack Uses Domains Identical to Known Safe Sites
Index Tech: Cirill betűkkel hamisítják a weboldalakat
www.xn--e1awd7f.com
K: Ebből mi az utolsó link? Ha rákattintok, megsemmisül a gépem?
V: Nem, nem történik semmi, csak a böngésző címsorát kell megnézned: ha az jelenik meg, hogy www.еріс.com, akkor a böngésződ támadható ilyen módon. (Ellenőrzésképpen vágd ki innen ezt a négy betűt: еріс és másold át egy hexa-kód megmutatásra képes szövegszerkesztőbe.)
— Urlencode (%-szekvenciák) —
K: A fentebb említett %-szekvenciákat milyen szabvány definiálja?
V: Az RFC3986 2.1-es fejezete írja la a Percent-Encoding-ot; a legfontosabb tudnivaló, hogy a %-szekvencia mindig három karakterből áll (%<hexdig1><hexdig2>) és egyetlen bájtot reprezentál. A bájt értelmezése ASCII-kompatibilis kell legyen (pl. ISO-8859-x, UTF-8). Nem kell (bár megengedett) %-szekvenciával ábrázolni az a-zA-Z0-9~_-. karaktereket, minden mást igen. (Ez azért kontextustól függ, lásd például lentebb a wget-nél.) Speciális eset a szóköz (ASCII 0x20): egyes változatok a %20 szekvencia helyett/mellett a + jelet használják a szóköz ábrázolására.
K: Tehát a %-szekvenciáknál nincs előírva, hogy mondjuk UTF8-at vagy ISO-8859-2-t használjak?
V: Így van, az RFC csak ASCII-karakterekkel foglalkozik, tehát arról nem mond semmit, hogy például valamely kontextusban a %C3%95 UTF8-szerint egy darab Õ karaktert jelent-e, vagy két karaktert (és az utóbbi esetben milyen kódolás szerint).
K: HTTP protokoll esetén hol találkozom én ilyen %-szekvenciákkal?
V: Az URL-fájl/path részében (a példát lásd fentebb); a GET-paraméterben (A ? utáni rész, más néven: Querystring); valamint a HTTP-Body-ban, ha a Content-Type értéke application/x-www-form-urlencoded.
K: Nézzük konkrétan a PHP esetét: a GET/POST adatban lévő %-szekvenciákat milyen kódolás szerint értelmezi a PHP-motor?
V: A PHP-string típusa bájtok sorozata, tehát a felhasználói program feladata a bájtok értelmezése.
K: Akkor nézzük fordítva: a kliensprogram (böngésző) milyen kódolás szerint állítja elő a %-szekvenciákat a GET/POST adatmezőiben?
V: Általálában az illető FORM-ot tartalmazó oldal kódolásának megfelelően, de a FORM-nál is megadhatunk egy accept-charset értéket.
K: A wget-ről mit mondhatunk?
V: A következő információtöredékeket szedtem össze:
— Kódkészletek —

K: Jó választás az iso-8859-1 (avagy latin1)?
V: Nem, mert nincs benne őŐűŰ csak õÕûÛ.
K: Dehát sok helyen az az alapértelmezés!
V: És mégsem jó a magyar betűkhöz. Válassz inkább ezekből: iso-8859-2 (latin2), win-1250, utf-8.

K: És az igaz, hogy a latin2 (más néven iso-8859-2) ugyanaz, mint a win-1250?
V: Nem egészen. A magyar betűk ugyanott vannak mindkettőben, ez igaz; viszont a win-1250-ben van pár hasznos jel, ami a latin2-ből hiányzik, például az euro jele (0x80 €), a hárompont (0x85 …), az ndash (0x96 –), az mdash (0x97 —) és a kopirájt jele (0xA9 ©). A pontos lista unicode.org-on: 8859-2.TXT cp1250.TXT

K: És a csehszlovák/szerbhorvát betűk is ugyanott vannak a fenti két kódolásban?
V: Sajnos nem, például az Š latin2-ben 0xA9, win1250-ben 0x8A. (Újabb ok az utf8 használatára!)

K: Igaz, hogy a legtöbb baj az Ő és az Ű betűvel van? És miért?
V: Igaz, mégpedig azért, mert csak ezek nincsenek benne a latin1-ben (ami a legtöbb esetben az alapértelmezés), hanem helyettük Õ és Û van azon a kódon.

K: Azt hallottam, hogy ha azt írom helyettük, hogy &Otilde; és &Ucirc; akkor a fájl kódolásától függetlenül mindig jó lesz.
V: Ez majdnem igaz, a pontos információ az, hogy így a fájl kódolásától függetlenül mindig rossz lesz. Ha &-szekvenciákat akarsz, akkor használd ezeket: &#x150;=Ő, &#x151;=ő, &#x170;=Ű, &#x171;=ű.

K: Hol találok egy listát az összes ilyen &-szekvenciáról, hogy pl.: &hellip;=… vagy &beta;=β?
V: Mondjuk a w3.org-on: Character entity references in HTML 4. Természetesen a kódokat is használhatod, decimálisan vagy hexásan, pl.: &#915;=&#x393;=&Gamma;=Γ.

K: Kódolásra visszatérve, lehet, hogy érdemes lenne áttérnem az utf8-ra?
V: Nem lehetetlen, különösen, ha akár csak a távlati terveid között is szerepel orosz, ázsiai, eszperantó vagy klingon karakterek ábrázolása.

K: Már elkezdtem valamit alkotni, de most szeretném átkonvertálni egy másik kódkészletbe, mit tegyek?
V: Könnyen lehet, hogy a kedvenc szövegszerkesztőd is képes erre (keresgélj a 'Save As' menüpontnál), de ha nem, használj valami olyasféle programot, mint az iconv! (Még egyszer figyelmeztetlek: az egyetlen dolog, amit a 'BOM'-ról tudnod kell, az az, hogy nincs rá szükséged!)

K: Mit kell tudnom az UTF-7-ről?
V:Valószínűleg semmit, de egyszer kipróbálhatod (a -f (=from) opciót igazítsd a saját aktuális beállításodhoz):
echo 'árvíztűrő tükörfúrógép' | iconv -f latin2 -t utf-7
+AOE-rv+AO0-zt+AXE-r+AVE t+APw-k+APY-rf+APo-r+APM-g+AOk-p
Megj: További kódolások, amikről nem kell tudnod: UTF-1, UTF-5, UTF-6, UTF-9, UTF-18.
K: Ha már furcsa kódolásokról beszélünk, a cat -v milyen jeleket használ?
V: Két speciális jelölést használ, az egyik a ^kalap karakter, a másik a M- prefix. Egy táblázattal próbálom szemlélteni a működését:
ezt látjuk		ezt jelenti (karakterkód hexásan) megjegyzés
^A .. ^Z 		00..1A				  0x40-et levonunk a karakterkódból
^[ ^\ ^] ^^ ^_		1B..1F				  0x40-et levonunk a karakterkódból
normál ASCII karakter	20..7E
^?			7F				  egyedi jelölés
M-^A .. M-^Z		80..9A				  0x40-et hozzáadunk a karakterkódhoz
M-^[ .. M-^_		9B..9F				  0x40-et hozzáadunk a karakterkódhoz
M-normál ASCII karakter	A0..FE				  0x80-at hozzáadunk a karakterkódhoz
M-^?			FF				  egyedi jelölés
K: Ha nekem jó lenne az ISO-8859-2, de euró-jelet (€) is szeretnék, akkor használhatom az ISO-8859-16-ot?
V: Használhatod, de az űŰ nem ugyanott van a kettőben, vagyis kovertálni kell... akkor már jobban jársz a windows-1250-nel (abban a magyar betűk ugyanott vannak), vagy az utf-8-cal (univerzális, korszerű megoldás).
K: Tulajdonképpen mit szabványosít az Unicode?
V: Karakterekhez rendel számokat. Azt nem írja elő, hogy ezeket a számokat hogyan kell memóriában vagy fájlban tárolni.
K: De az legalább egy remek dolog, hogy ezek a számok sosem változnak!
V: Tulajdonképpen egyes tibeti és koreai karakterekkel azért történt ilyesmi, pl.:
    1.0  1.1  2.0
 ཀ 1000    –  F40
가 3400 3400 AC00
K: Nem az lenne a legjobb, ha egyszerűen Unicode-ot használnánk? Ugyebár minden karakterhez hozzárendeltek egy 0 és 65535 közötti (tehát két bájton tárolható) számot...
V: Az a szám már messze túl van a 65535-ön, például az &#127828;=&#x1f354;=🍔 egy hamburger. UTF-8-ban a kódja: f0 9f 8d 94 (ha a böngésződ nem talál olyan fontot, amiben benne van, akkor persze kérdőjelet/furcsa izét látsz). De még ha bele is férne két bájtba, akkor is két lehetőség lenne a tárolásra, a little-endian, meg a big-endian, szóval eleve nem lenne univerzális megoldás.
K: Franc. Akkor ezt nem is használják?
V: De igen, úgy hívják őket, hogy UCS-2LE és UCS-2BE. Minta:
$ echo -n 'tűrő' | iconv -f latin2 -t UCS-2LE | od -tx1
0000000  74 00 71 01 72 00 51 01
$ echo -n 'tűrő' | iconv -f latin2 -t UCS-2BE | od -tx1
0000000  00 74 01 71 00 72 01 51
K: Ezek közül valamelyik megegyezik az UTF-16-tal?
V: Az UTF16-LE és az UTF16-BE ezeknek továbbfejlesztett változatai, képesek minden unikódot ábrázolni, igaz nem fix hosszon. Az előbbi hamburgerrel kipróbálva:
$ echo -n $'\xf0\x9f\x8d\x94' | iconv -f utf-8 -t utf-16le | od -tx1
0000000 3c d8 54 df
$ echo -n $'\xf0\x9f\x8d\x94' | iconv -f utf-8 -t utf-16be | od -tx1
0000000 d8 3c df 54
K: Mik lennének ezek a négybájtos (avagy kétszer kétbájtos) szekvenciák?
V: Ezt a dolgot helyettesítő pár-nak hívják (surrogate pair); a pár két fele 1024 érték közül tárol egyet-egyet (az első a d800-dbff tartományból, a második a dc00-dfff tartományból vesz fel értéket), így összesen 1048576 kódot lehet így tárolni. Valahogy így tudnám ezt táblázattal szemlélteni (minden kód hexadecimális, az unikód elé U+ -t írok, hogy gyakoroljuk ezt a jelölést, továbbá feltüntetem az UTF8-as és a CESU8-beli kódot is):
  Unikód   UTF-16     UTF-8        CESU-8
     U+0   0000       00           00
  U+D7FF   D7FF       ED-9F-BF	   ED-9F-BF
-- itt 2048 érték kimarad, nem reprezentál karaktert --
  U+E000   E000       EE-80-80     EE-80-80
  U+FFFF   FFFF       EF-BF-BF     EF-BF-BF
 U+10000   D800 DC00  F0-90-80-80  ED-A0-80 ED-B0-80
 U+103FF   D800 DFFF  F0-90-8F-BF  ED-A0-80 ED-BF-BF
U+10FC00   DBFF DC00  F4-8F-B0-80  ED-AF-BF ED-B0-80
U+10FFFF   DBFF DFFF  F4-8F-BF-BF  ED-AF-BF ED-BF-BF
K: Igazából nem U+xxxx illete U-xxxxxxxx a hivatalos jelölés (vagyis négy illetve nyolc hexa számjegy)?
V: De igen, ha programokkal kommunikálsz, használd így; ha viszont emberekkel, akkor talán elvárhatsz némi rugalmasságot az olvasótól.
K: Például hol használnak ilyen UTF-16-ot, és miért?
V: Például MS Windows, Oracle, Java, AIX... És azért, mert volt idő, amikor még úgy tűnt, hogy 16 biten el fog férni az összes unikód (bár ezt egy kicsit nehéz elhinni, ha pl. a kínai szóírásra gondolunk), utána viszont már késő volt teljes átállásra, tehát valami kvázi-kompatibilis megoldást kellett tákolni, ez lett az UTF-16. Azok a programok/platformok, amik később tértek át az unikódra, rendszerint az UTF-8-at használják.
K: A kétféle UTF-16 után azt tippelem, hogy UTF-32-ből is kettő van: UTF32-LE és UTF32-BE...
V: Stimmel. A jó hír viszont az, hogy ez legalább fixhosszú kódokból áll. A rossz pedig az, hogy nagyon sok a kihasználatlan (nulla értékű) bit.
K: És van valami módszer, amivel ezt a sok szép lehetőséget azonosítani lehet?
V: Ez lenne a BOM jelentősége, rögtön a fájl legelején, az alábbiak szerint:
EF-BB-BF    UTF-8
FF-FE	    UTF-16LE
FE-FF	    UTF-16BE
FF-FE-00-00 UTF-32LE
00-00-FE-FF UTF-32BE
K: Ebben a FAQ-ban sok helyen van szó az UTF-8-ról, összefoglalhatnánk itt a legfontosabb tudnivalókat?
V: Na nézzük listában:
Egy kis ábra az egyes szekvenciákról:
bájtok száma:  1	      2		     3		    4
hasznos bitek: 7	      11	     16		    21
első bájt:     00..7f	      c2..df c0..df  e0..ef	    f0..f4   f0..f7
minimum:       00	      c2 80	     e0 a0 80	    f0 90 80 80
maximum:       7f	      df bf	     ef bf bf	    f4 8f bf bf
U+minimum:     U+0	      U+80	     U+800	    U+10000
U+maximum:     U+7f	      U+7ff	     U+ffff	    U+10ffff U+1fffff
	      +-----------+  +-----------+  +-----------+  +-----------+ 
	      | 0xxx xxxx |  | 110x xxxx |  | 1110 xxxx |  | 1111 0xxx |
	      +-----------+  +-----------+  +-----------+  +-----------+
			     | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |
			     +-----------+  +-----------+  +-----------+
					    | 10xx xxxx |  | 10xx xxxx |
					    +-----------+  +-----------+
							   | 10xx xxxx |
							   +-----------+
Megj.: Itt a 'minimum' nem azt jelenti, hogy annál kisebb értéket ne lehetne ábrázolni az adott bájtsorozattal, hanem azt, hogy a szabvány szerint hibásnak kell tekinti ilyen bájtsorozatot, amelyik a minimumnál kisebb értéket repretentál.
Az érdekesség kedvéért egy ábra arról, hogy mi volt korábban, amikor még 5-6 bájtos szekvenciák is lehettek :
bájtok száma:  1	      2		     3		    4		   5		  6
hasznos bitek: 7	      11	     16		    21		   26		  31
első bájt:     00..7f	      c2..df c0..df  e0..ef	    f0..f7	   f8..fb	  fc..fd
minimum:       00	      c2 80	     e0 a0 80	    f0 90 80 80    f8 88 80*3	  fc 84 80*4
maximum:       7f	      df bf	     ef bf bf	    f7 bf bf bf    fb bf bf*3	  fd bf bf*4
U+minimum:     U+0	      U+80	     U+800	    U+10000        V+200000       V+4000000
U+maximum:     U+7f	      U+7ff	     U+ffff	    V+1fffff	   V+3ffffff	  V+7fffffff
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+ 
	      | 0xxx xxxx |  | 110x xxxx |  | 1110 xxxx |  | 1111 0xxx |  | 1111 10xx |  | 1111 110x |
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
			     | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |
			     +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
					    | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |
					    +-----------+  +-----------+  +-----------+  +-----------+
							   | 10xx xxxx |  | 10xx xxxx |  | 10xx xxxx |
							   +-----------+  +-----------+  +-----------+
									  | 10xx xxxx |  | 10xx xxxx |
									  +-----------+	 +-----------+
											 | 10xx xxxx |
											 +-----------+
Megj.: a V+szám jelölést csak ennek a példának a kedvéért találtam ki, hogy hangsúlyozzam, hogy a jelenlegi szabvány szerint nem lehet ilyen unikód.
K: Még további UTF-8 változatok is vannak?
V: Van még egy UTF-8-MOD nevű speciális változat, amit EBCDIC-kel kapcsolatban szokás használni: UTF-EBCDIC (avagy UTFE):
bájtok száma:  1	      2		     3		    4		   5
hasznos bitek: 7(7.25)	      10	     14		    18		   21
első bájt:     00..9f	      c5..df c0..df  e1..ef e0..ef  f0..f7	   f8..f9 f8..fa
minimum:       00	      c5 a0	     e1 a0*2	    f0 a0*3	   f8 a0*4
maximum:       9f	      df bf	     ef bf*2	    f7 bf*3	   f9 a1 bf*3 bf*4
U+minimum:     U+0	      U+a0	     U+400	    U+4000	   U+40000
U+maximum:     U+9f	      U+3ff	     U+3fff	    U+3ffff	   U+10ffff U+1fffff
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+ 
	      | 0xxx xxxx |  | 110x xxxx |  | 1110 xxxx |  | 1111 0xxx |  | 1111 100x |
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
	      vagy	     | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
	      | 100x xxxx |		    | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
	      +-----------+		    +-----------+  +-----------+  +-----------+
							   | 101x xxxx |  | 101x xxxx |
							   +-----------+  +-----------+
									  | 101x xxxx |
									  +-----------+
Az így kapott bájtsorozatokat úgy kell az adott EBCDIC-változatba konvertálni, mintha ISO-8859-1 kódban lennének. (Érdemes tudni, hogy az EBCDIC-nek számos inkompatibilis változata van.)
Ennek a módszernek az előnye az, hogy a 0x80..0x9f értekek (binárisan 100xxxxx), amelyek az ISO-8859-es kódolásban C1 vezérlőkaraktereket jelentenek nem szerepelnek a több-bájtos szekvenciákban.
K: Ez miért lenne jó?
V: A hagyományos egybájtos kódolásra felkészített programok ezeket a bájtokat vezérlőkarakternek tekinthetnék, például az U+85 kódú NL (vagy NEL) – illetve annak EBCDIC-megfelelője – soremelést jelent(het).
K: És ez mitől EBCDIC-specifikus?
V: Igazából nem az, de ASCII-kiterjesztésből sok van, és nem mindegyik tekinti vezérlőkarakternek ezeket a kódokat (lásd pl ISO8859-2 vs windows-1252), tehát kevésbé valószínű, hogy a programok működését zavarnák ezek a kódok. Azonkívül az EBCDIC-et használó mainframe-eken gyakori, hogy bevált programokat változatlanul futtatnak évtizedeken át, ezért itt a kompatibilitási szempontok fontosabbak.
K: Az UTF-8-nál említetted, hogy hosszabb szekvenciákkal több karaktert is lehet(ne) ábrázolni (ha az Unicode értéktartományát nem csökkentették volna). Ez itt is lehetséges?
V: Igen, valahogy így:
bájtok száma:  1	      2		     3		    4		   5		  6		 7
hasznos bitek: 7(7.25)	      10	     14		    18		   22		  26		 31
első bájt:     00..9f	      c5..df c0..df  e1..ef e0..ef  f0..f7	   f8..fb	  fc..fd	 fe..ff
minimum:       00	      c5 a0	     e1 a0*2	    f0 a0*3	   f8 a0*4	  fa a0*5	 fe a0*6
maximum:       9f	      df bf	     ef bf*2	    f7 bf*3	   f9 bf*4	  fb bf*5	 ff bf*6
U+minimum:     U+0	      U+a0	     U+400	    U+4000	   U+40000	  V+400000	 V+4000000
U+maximum:     U+9f	      U+3ff	     U+3fff	    U+3ffff	   V+3fffff	  V+3ffffff	 V+7fffffff
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
	      | 0xxx xxxx |  | 110x xxxx |  | 1110 xxxx |  | 1111 0xxx |  | 1111 10xx |  | 1111 110x |  | 1111 111x |
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
	      vagy	     | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
	      +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
	      | 100x xxxx |		    | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
	      +-----------+		    +-----------+  +-----------+  +-----------+  +-----------+  +-----------+
							   | 101x xxxx |  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
							   +-----------+  +-----------+  +-----------+  +-----------+
									  | 101x xxxx |  | 101x xxxx |  | 101x xxxx |
									  +-----------+  +-----------+  +-----------+
											 | 101x xxxx |  | 101x xxxx |
											 +-----------+  +-----------+
													| 101x xxxx |
													+-----------+
K: Már volt szó a CESU-8-ról, de mi is pontosan?
V: Az UTF-8 változata vagy rokona; azzal azonos a U+0..U+d7ff és U+e000..U+ffff tartományokon (emlékezzünk, d800 és dfff között nincsenek karakterkódok); az afölötti kódokat az UTF-16-nál leírt helyettesítő párok UTF-8-as kódolásával alakítja hatbájtos szekvenciává, pl.:
$ echo '🍔' | od -tx1  # => f0 9f 8d 94 – UTF-8
$ echo '🍔' | iconv -f UTF-8 -t UTF-16BE \
            | od -tx1  # => d8 3c df 54 – UTF-16
$ echo '🍔' | iconv -f UTF-8 -t UTF-16BE \
            | recode UCS-2BE..UTF-8 \
            | od -tx1  # => e3 b3 98 e5 93 9f – CESU-8
K: Nagyon szép ez a hatbájtos szekvencia, de miért vetted elő ezt a recode nevű programot? Ha jól látom, ugyanarra való, mint az iconv (csak más szintaktikával).
V: Az egyik gond az, hogy a kettő egyike sem ismeri a CESU-8-at (ezért kell két lépésben konvertálni), a másik az, hogy (ahogy fentebb mondtuk) a d800..dfff tartomány "tiltott", ezért az iconv nem is hajlandó velük foglalkozni, a recode viszont "engedékenyebb".
— C-programozás —
K: Ha én mondjuk C-programozó vagyok, akkor a wchar_t mit fog jelenteni az UCS-*, UTF-16*, UTF-32* lehetőségek közül?
V: Platformfüggő.
K: Hogy mi van?!
V: Tudom, hogy ez most úgy hangzik, mintha nem lehetne portábilisan használni, de a valóság az, hogy nem lehet portábilisen használni. Tehát ha mondjuk az a vágyad, hogy írj egy platformfüggetlen programot, ami előállít egy fájlt pl. UTF-16LE/-16BE/-32LE/-32BE kódolásban, akkor abban a wchar_t egycsapásra nem segít semmit. Tesztprogram:
/* wchartest.c */

#include <stdio.h>
#include <wchar.h>

int main (void)
{
    wchar_t wstring [] = { 0xf6, 0x151, 0xfc, 0x171 /* o: o" u: u" */ };
    size_t i;

    for (i=0; i<sizeof(wstring); ++i) {
        unsigned c= ((unsigned char *)wstring)[i];
        if (i!=0 && (i%sizeof(wchar_t)==0)) printf ("-");
        printf ("%02x", c);
    }
    printf ("\n");
    return 0;
}
Ennek a kimenete különféle platformokon:
linux, x86:      f6000000-51010000-fc000000-71010000
Windows, x86:    f600-5101-fc00-7101
AIX, PowerPC/32: 00f6-0151-00fc-0171
AIX, PowerPC/64: 000000f6-00000151-000000fc-00000171
K: Na jó, de én nem is így akarom a programban rögzíteni a stringeket, hanem L'ä' és L"öőüű" formában. Ebben van valamilyen problémás rész vagy hibalehetőség?
V: Annyi, hogy a compiler-nek tudnia kell, hogy milyen kódolásban van a forrásprogram. Hogy ez hogyan történik, az platformfüggő lehet; ha nem adod meg, akkor valamiféle alapértelmezés fog érvényesülni. Például gcc esetén az -finput-charset való erre, pl (linux).:
# a source latin2-ben van
$ gcc -finput-charset=iso-8859-2 -o wchartest_l wchartest_l.c
$ ./wchartest_l
f6000000-51010000-fc000000-71010000-00000000

# a source utf8-ban van
$ gcc -finput-charset=utf-8 -o wchartest_u wchartest_u.c
f6000000-51010000-fc000000-71010000-00000000
K: Ha eltévesztem, akkor fordítási hibát kapok, vagy a futás lesz rossz?
V: Igen. (A fordító észreveheti, hogy a latin2 (általában) nem valid utf8, de a fordítva ez nem igaz.)
K: MS Windows esetén micsoda a wchar_t?
V: Intel platformon 16-bites little endian, a 16-biten el nem férő karaktereket két egymást követő wchar_t tárolja (lásd: UTF-16LE, surrogate pairs).
K: És igaz, hogy majdnem a teljes Windows API-t 'megduplázták', minden hagyományos stringeket használó függvénynek lett egy párja, ami UTF-16-os ("széles" avagy "wide") stringeket használ?
V: Igaz (pl. a CreateWindow makró a CreateWindowA és CreateWindowW függvények valamelyikévé fog kifejtődni), de lehetséges olyan programot írni, ami egy #define-tól (UNICODE) függően lesz "keskeny-" vagy "széles-" karakteres.
TCHAR name= _T("Őrült Űrhajós");
size_t namelen= _tcslen(name);
K: És milyen függvényekkel konvertálhatok Windows-ban "keskeny" és "széles" között?
V: Ezeket használhatod: MultiByteToWideChar WideCharToMultiByte. Nevükkel ellentétben nem csak multibájtról/-ra tudnak konvertálni (lásd itt: Code Page Identifiers, valamint használhatsz default ansi kód és default oem kód értékeket is (CP_ACP és CP_OEMCP), ha platformfüggő működést akarsz elérni).
K: C-programban milyen oktális/hexa szekvenciákat használhatok karakter- és stringliterálokban?
V: Az egyre újabb szabványok egyre újabb lehetőségeket hoztak:
\000	    --  egy-három oktális számjegy a 000-377 tartományból
\x00	    --  egy vagy több hexadecimális számjegy (a hossz nincs korlátozva)
\u0000      --  négy hexadecimális számjegy (unikód)
\U00000000  --  nyolc hexadecimális számjegy (unikód)
Megjegyzések:
K: Mit kell tudnom a C11-es szabvány szerinti új char16_t és char32_t típusokról?
V: Ezek az uchar.h-ban definiált előjel nélküli integer típusok, amelyek 16- illetve 32-bitesek. Legalább.
K: Legalább?! Ugye jobb lesz nekem, ha nem gondolok bele abba, hogy mit jelent ez a legalább?
V: Határozottan. Nézzük meg inkább, hogyan tudsz literálokat definiálni ezekhez a típusokhoz:
    wchar_t  cw=    L'ő', sw[]=  L"tűzvész"; /* platformfüggő */
    char16_t c16=   u'ő', s16[]= u"tűzvész"; /* UTF-16 */
    char32_t c32=   U'ő', s32[]= U"tűzvész"; /* UTF-32 */
    char                  su8[]= u8"tűzvész";/* UTF-8 */
K: Az utolsó az UTF-8, ugye? De azt minden további nélkül tudok használni, nemde?
V: Igen, ha a forrásprogram UTF-8-ban van. Az u8-nál viszont a fordítóprogram konvertál UTF-8-ra. Ehhez persze tudnia kell, hogy milyen karakterkészetetben van a forrásprogram. Ha ez az információ hiányzik vagy hibás, akkor fordítási hiba és/vagy hibás működés lesz belőle (lásd fentebb). Persze ugyanez igaz a L/u/U literálokra is.
K: gcc-nél említettük a -finput-charset opciót. Ez csak az L/u/U/u8 típusú literálokra vonatkozik, a hagyományosakra nem?
V: Hagyományos észjárással így képzelnénk, de igazából a gcc a "sima" string- és karakterliterálokat is konvertálja "input-charset"-ről UTF-8-ra.
Szerencsére rá lehet venni, hogy ezt visszacsinálja, ha megadjuk a -fexec-charset opciót, ugyanazzal az értékkel,
pl. ha a fenti stringeket teszteljük egy kis programmal (amit latin2-ben rögzítünk):
gcc -std=c11 -finput-charset=ISO-8859-2 -fexec-charset=ISO-8859-2 tuzvesz.c -o tuzvesz
./tuzvesz
"sima" string:      74 fb 7a 76 e9 73 7a
wchar_t string:     74 00 00 00 71 01 00 00 7a 00 00 00 76 00 00 00 e9 00 00 00 73 00 00 00 7a 00 00 00
char16_t u"string": 74 00 71 01 7a 00 76 00 e9 00 73 00 7a 00
char32_t U"string": 74 00 00 00 71 01 00 00 7a 00 00 00 76 00 00 00 e9 00 00 00 73 00 00 00 7a 00 00 00
utf8 u8"string":    74 c5 b1 7a 76 c3 a9 73 7a
Megjegyzés: Ne felejtsük el, hogy a byte-order és a wchar_t mérete platformfüggő.
K: Szóval a gcc-ben -finput-charset opciót használhatom. És clang esetén?
V: Az opció ugyanaz, de a használható értékkészlet egy kicsit szűkebb: csak az UTF-8 értéket választhatod.
K: Nem baj, az iconv segít, ugye?
V: Persze. Feltéve, hogy csak L"", U"", u"", u8"" formájú stringek és karakter-konstansok vannak a programban, mert ha hagyományos stringek (karakterek) is vannak benne, akkor a program mást fog csinálni, mint a konverzió előtt (már ha egyáltalán lefordul).
Mindenesetre itt egy Makefile-részlet az érdekesség kedvéért:
%_clang.c: %.c
    (echo '#line 1 "$<"';\
     iconv -f ISO-8859-2 -t UTF-8 "$<") \
    >"$@"
K: A Borland-féle BCC32 fordító esetén mi a -finput-charset megfelelője?
V: A -CP<kódlapszám> opció, pl.:
bcc32 -v -CP1250 mysource.c
K: A Microsoft MSC compiler esetén milyen opciókat használhatok erre?
V: A forrásprogram kódolását a /source-charset opcióval állíthatjuk be, a 'kimenő' kódolást pedig /execution-charset opcióval, illetve van egy összevont /utf-8 opció is, ami mindkettőt UTF-8-ra állítja.
— Automatikus felismerés —
K: Van egy program, ami automatikusan felismeri a kódolást...
V: Nincs.
K: De, mondom, megvizsgálja a fájlt, és kiírja, hogy 'ANSI'...
V: Felejtsd el, nincs ilyen hogy 'ANSI', és nincs olyan, hogy automatikus felismerés.
K: Dehát még a Windows API-ban is benne van egy ilyen függvény: IsTextUnicode
V: És mégsem. Az ilyen eszközök kb. ilyesmire képesek:
K: Na jó, de akkor pontosan mi az az ANSI?
V: Ha egy program mondja neked, akkor azt jeleni, hogy 'valószínűleg nem UTF8'; ha te mondod egy Windows-os programnak, akkor a default egybájtos kódolást jelenti, ami lehet pl. az EASTEUROPE_CHARSET néven is ismert windows-1250, de lehet a nyugat-európában szokásos windows-1252. Vagy más.
K: Akkor mit tegyek?!
V: Mivel te ember vagy, a kódolás meghatározásához használd a természetes intelligenciádat, a hexviewert, meg ennek a fájlnak a végén a táblázatot. (Ha a fáljt egy ember állította elő, őt is megkérdezheted, de jó eséllyel nem fogja tudni; sőt, még csak be sem ismeri, hogy nem tudja, hanem kimondja az első/egyetlen kódolás nevét, ami az eszébe jut.)
— Iconv —
K: Sokat emlegeted ezt az iconv-ot, de igazából mi az?
V: Egy program (iconv executable) és egy programkönyvtár (libiconv) együtt; ha a te gépeden gyárilag nincs ilyen, akkor a GNU libiconv telepítését javaslom.
K: Ez a libiconv állítólag mindenre jó, nekem mégsem működik pl. a CP852-vel.
V: Lehet, hogy a te gépeden egy hiányos változat van, így ellenőrizheted:
$ iconv -l | grep 852
852 CP852 IBM852 CSPCP852
K: Jó, és ha tényleg nincs találat?
V: Fordít(tat)sd újra, de a configure-nél add meg a --enable-extra-encodings opciót!
K: Én?!
V: Vagy te, vagy a rendszergazda, aki azért kap fizetést, hogy a gépet üzemeltesse.
K: És ha pl. Perl CGI-t használok, abban is van iconv?
V: Akad: Text-Iconv.
K: Lehet saját kódtáblákkal bővíteni a GNU libiconv-ot?
V: Lehet, de a részletek leírása helyett csak két példafájlt adok, kiindulásnak jó lehet: IBM-037.TXT IBM-1047.TXT
K: Az iconv-on kívül milyen segédprogramokat használhatunk konverziós feladatokhoz?
V: Az iconv-hoz hasonló a recode, hívási példa:
echo 'Αγαμέμνονας' | recode UTF8..UCS-2BE | od -tx2 --endian=big
0000000 0391 03b3 03b1 03bc 03ad 03bc 03bd 03bf
0000020 03bd 03b1 03c2 000a
Az uni2ascii/ascii2uni páros UTF8 és annak ASCII-reprezentációi között konvertál, pl.:
echo 'árvíztűrő tükörfúrógép' | uni2ascii -q -l -aU
\u00e1rv\u00edzt\u0171r\u0151 t\u00fck\u00f6rf\u00far\u00f3g\u00e9p
Sajnos az ascii2uni nem hibátlan a \u szekvenciák kezelésében (egy kísérlet a javításra itt látható), helyette a Java native2ascii nevű segéprogramját ajánlom, példa a használatára:
native2ascii -encoding UTF-8          normal.file     usequences.file
native2ascii -encoding UTF-8 -reverse usequences.file normal.file
— JavaScript —
K: JavaScript-ben hogyan lehet kódokat használni a stringekben?
V: \-szekvenciákkal, nevezetesen \xDD és \uDDDD; az előbbi két hexa számjegyet fogad, az utóbbi négyet, mindkét esetben unikódban. Pl:
<BUTTON onclick='alert ("\xe1rv\xedzt\u0171r\u0151 t\xfck\xf6rf\xfar\xf3g\xe9p");'>Próba</BUTTON>
Figyeljük meg, hogy az ő-t és az ű-t csak a hosszabb formával lehet megadni!
K: És ha U+ffff-nél nagyobb unikódot akarok használni?
V: Helyettesítő párt (surrogate pair) használva, pl. az U+1f354 kódú hamburger(🍔) esetén:
<button onclick='alert ("\\ud83c\\udf54 = \ud83c\udf54");'>Próba</button>
Egy másik lehetőség (ami újabb fejlesztés, tehát nem biztos, hogy mindenhol használható) ez szintaxis: \u{1-8 hexa számjegy}, pl:

K: JavaScriptről szólva, ha a window.open-nel nyitok meg egy ablakot, de úgy, hogy az első paraméter üres string, és az ablak tartalmát document.write-okkal állítom elő, az milyen kódolású lesz?
V: Tapasztalataim szerint UTF-8, pl:

K: Találtam egy encodeURIComponent nevű függvényt, amit tudnék használni a GET/POST paraméterek kódolásához (pl. Ajax alkalmazásánál), de nem tudom beopciózni, hogy milyen kódolás szerint képezze a hexakódokat, fixen UTF-8-at használ, pl: 'répa' -> 'r%C3%A9pa'.
V: Én sem tudom. A legjobb megoldás, ha a fogadó oldalon (PHP, CGI) is UTF-8-at használsz, vagy ha nem, akkor konvertálsz róla (iconv) a használt kódra.
K: Konvertálhatok, igen, de akkor nem lehet ugyanazt a php programot használni hagyományos meghívással és pl. Ajax-szal.
V: Megpróbálhatod a paraméterek nevével jelezni a kódolást is, pl egy _U a név végén UTF-8-at jelezhet, a feldolgozó program ebből tudhatja, hogy kell-e konvertálni, egyben az esetleges későbbi átállást is fokozatossá lehet így tenni). Pl:
valami.php?zoldseg=r%E9pa      -- 'hagyományos hívás', latin2
valami.php?zoldseg_U=r%C3%A9pa -- 'encodeURI-s hívás', utf-8
— PHP —
K: Milyen \-szekvenciák használhatók PHP-ben a string-literálokban?
V: Egyszeres idézőjelek (avagy 'apostolok') között csak \' és \\ használható, jelentésük ' és \.
Kettős idézőjelek (avagy "macskakörmök") között többféle szekvencia használható (lásd itt), a mi szempontunkból relevánsak ezek:
\1 \12 \123  oktális kód, 1-3 számjegy, binárisan értődik, nincs konverzió
\xa \xab     hexadecimális kód, 1-2 számjegy, binárisan értődik, nincs konverzió
\u{1f354}    hexadecimális kód, egy vagy több számjegy,
             unicode-ban értődik, utf8-ra konvertálódik,
             php7-től használható
Megjegyzés: Az utóbbi eredménye mindenképpen UTF8 lesz, nem lehet átállítani.
K: Tehát \uXXXX szintaxist nem használhatok, csak \u{XXXX} formát (PHP7-től kezdve)?
V: Nem, de van kerülőút: használhatod erre a célra a json_decode függvényt; ennek az eredménye mindig UTF-8 lesz, helyettesítő párok használhatók; pl:
    $utf8str= json_decode ('"\u0150 \u0151 \u0170 \u0171 \ud83c\udf54"');
    printf ("s=%s  hex=%s\n", $utf8str, bin2hex ($utf8str));

    s=Ő ő Ű ű 🍔  hex=c590 c591 c5b0 c5b1 f09f8d94

K: Az jó, ha a header-t nem teszem minden más kiírás elé, hanem az ob_* függvényekkel kavarok?
V: Szerintem hülyeség, de ha neked jó...

K: Pontosan hogyan kell használni az utf8_encode függvényt?
V: Sehogy, mert csak latin1-re működik. Válassz ezekből: iconv, mb_convert_encoding,
K: Akkor talán az utf8_decode függvényt sem érdemes használni?
V: Bingó! Az utf8->latin1 konverzió során az őŐűŰ betűk megszűnnek létezni.
K: Vannak a PHP-nek utf8-as kódolású stringek kezelésére szolgáló függvényei?
V: Akadnak: PHP: Multibyte String - Manual Pl.:
$elso_szo= mb_substr ("Árvíztűrő tükörfúrógép", 0, 9, "UTF-8");
Megj: Nem kell mindig kiírni a kódkészletet (vagyis az UTF-8-at), ha használod az mb_internal_encoding függvényt.

K: Milyen bajt okozhat, ha pl. a hagyományos substr függvényt használom?
V: Mondjuk az, hogy ügyesen kettévágsz egy utf8-szekvenciát...

K: Mit tegyek, ha az fgetcsv függvény hibásan működik, ha ékezetes betűk vannak a mezők elején?
V: Előzőleg egy setlocale (LC_CTYPE, "...") hívás segíthet. (Szerk. megj.: A problémát nem tudtam reprodukálni, a PHP verziójától is függhet.)

K: Igaz, hogy a htmlentities függvény is okozhat gondot?
V: Okozhat, mivel ez a függvény mindent &-szekvenciává alakít, amit egyáltalán át lehet alakítani; ez magában foglalja a magyar ékezetes betűket is, viszot a latin2-t nem támogatja (még ha meg is adjuk a harmadik paraméterben), vagyis az Ű-ből például &Ucirc; lesz (eredménye: Û). UTF-8 esetén az őŐűŰ betúket nem alakítja át. (Ez persze nem akkora baj, hiszen a többit sem kellene átalakítania.)

K: Akkor mit használjak helyette?
V: A htmlspecialchars-t, ami csak az alábbiakat konvertálja: & < > ' " (ez utóbbi kettő opcionális, lásd a leírásban: ENT_NOQUOTES=egyiket sem, default=csak a macskakörmöt, ENT_QUOTES=mindkettőt)

K: A htmlspecialchars-ról szólva, mi a harmadik paraméter, az encoding jelentősége?
V: Az, hogy fixen 'ISO-8859-1'-et kell odaírni, hogy jól működjön, függetlenül attól, hogy milyen kódolást használsz. Ez is volt az alapértelmezés az 5.4-es verzió előtt, de akkor megváltoztatták 'UTF-8'-ra, ami azt ereményezi, hogy az UTF-8-ként nem értelmezhető input-stringre üres stringet ad válaszul. (Hibaüzenet nélkül persze.)
Megj.: Kérlek, ne értelmezd ezt úgy, hogy szerintem az ISO-8859-1 kódolás jó lenne a magyar betűkhöz, mert nem így van. Csakis és kizárólag a PHP hibája, hogy ezen függvény ezen paraméterében nem lehet sem 'ISO-8859-2'-t, sem 'BÁRMI'-t megadni (hanem az 'ISO-8859-1' jelenti azt, hogy 'BÁRMI').
Kieg.: az 5.6-os verzióban ismét változott az alapértelmezés, ini_get('default_charset') az új érték. (Ez persze semmit sem változtat az előbbiek érvényességén.)
K: A már átalakított &-szekvenciákat hogyan tudnám visszacsinálni?
V: A html_entity_decode fügvénnyel. Akkor könnyebb használni, ha UTF-8-ban dolgozol, latin2 esetén az iconv-ra is szükség van:
function decode_utf8 ($s)
{
    return html_entity_decode ($s, ENT_QUOTES, 'UTF-8');
}

function decode_latin2 ($s)
{
    $u= html_entity_decode ($s, ENT_QUOTES, 'UTF-8');
    return iconv ('UTF-8', 'ISO-8859-2', $u);
}
K: A quoted_printable_encode és quoted_printable_decode függvények milyen karakterkódolás esetén alkalmazhatók?
V: Ezek bájtsorozatokkal dolgoznak, tehát erre nincs korlátozás, lehet például UTF8, UTF16 vagy bármi más.
K: A base64_encode és base64_decode és függvények milyen karakterkódolás esetén alkalmazhatók?
V: Ezek bájtsorozatokkal dolgoznak, tehát erre nincs korlátozás, lehet például UTF8, UTF16 vagy bármi más.
K: Base64-ről szólva, Van beépített függvény Base64url-hez is?
V: Úgy látom, nincs; a Wikipedián leírt különbségek alapján házilag kell valamit tákolni, pl:
function base64url_encode (string $in) {
    $tmp= base64_encode ($in);
    $tmp= rtrim ($tmp, '=');
    $tmp= preg_replace ('/\s/', '', $tmp);
    $tmp= strtr ($tmp, '+/', '-_');
    return $tmp;
}

function base64url_decode (string $in) {
    $tmp= strtr ($in, '-_', '+/');
    $tmp= base64_decode ($tmp, false);
    return $tmp;
}
K: Azt már értem, hogy az adatbázisba nem tudok akármilyen stringet beletenni, hanem némi escape-elésre van szükség (legalábbis ha nem lehet bind-változókat használni) pl.: mysql(i)_real_escape_string, de úgy látom, hogy (legalábbis bizonyos szervereken), valaki más is csinál valami hasonlót, ezzel szépen elrontva az adataimat!
V: Ez a magic_quotes_gpc nevű beállítás a php.ini-ben; ha nem vagy rendszergazda a gépen, akkor nem tudod kikapcsolni, hanem a programból kell a stripslashes függvényt használni, pl:
$pwd = $_REQUEST ['jelszo'];
if (get_magic_quotes_gpc ()) {
  $pwd = stripslashes ($pwd);
}
$mysql_pwd = mysql(i)_real_escape_string ($pwd, $mysql_conn);

Kieg: Jó hír, hogy az 5.4-es verzióban a magic_quotes megszűnt.

K: Hol is van ez a php.ini nevű configfájl?
V: Platformfüggő, de a phpinfo nevű fügvény elárulja:
$ echo '<?php phpinfo(); ?>' | php 2>/dev/null | \
    grep "Loaded Configuration File"
Loaded Configuration File => /usr/local/lib/php.ini

K: Első problémám: hol van itt a webserver meg a böngésző?
V: Sehol, ez egy standalone PHP volt, ha még nem ismered, akkor sürgősen barátkozz meg vele.
K: De ez nem megy Windows-ban!
V: Kicsit lejjebb olvashatsz a PHP használatáról Windows alatt.
K: Második problémám: tényleg kiírt egy fájlnevet, de olyan file nincs is a gépemen!
V: Akkor jó esélyed van rá, hogy ha lenne ilyen fájlod, akkor azt használná.
K: Hogyan csináljak?! Én csak programozó vagyok, nem fájlteremtő feketemágus!
V: Valószínűleg már van is ott két minta, php.ini-production és php.ini-development néven. Ha nem tudod, hogy melyikből indulj ki, akkor válaszd a development-et.
K: Windows-ban is használható a PHP? És a stand-alone változat is?
V: Mindkettőre igen a válasz; a stand-alone futtatható program a PHP.EXE; ha kényelmesen akarod használni, jól teszed, ha a PHP könyvtárát (tipikusan C:\PHP) elhelyezed a PATH-on.
K: Windows-ban is használhatók a PHP-bővítmények, mint például a FPDF?
V: Igen; telepítheted őket, ahová jónak gondolod, csak ne felejtsd el a php.ini-ben az include_path-t beállítani!
Példa:
C:\> mkdir \Php-Ext\Fpdf
C:\> cd \Php-Ext\Fpdf
C:\Php-Ext\Fpdf> unzip C:\download\FPDF17.ZIP
C:\Php-Ext\Fpdf> find "include_path" c:\php\php.ini
include_path=".;C:\PHP-EXT"
Megjegyzés: egy kis Windows-os minta batch-fájlt láthatsz itt is.
Egyéb Windows-os kérdések a FAQ-ban itt találhatók.
K: Ha egy pillanatra visszatérhetnénk a UNIX-hoz, igaz, hogy a php.ini helye nincs egészen kőbe vésve, különösen akkor nem, ha forrásból telepítem a PHP-t?
V: Ez igaz, ha nem vágysz kellemetlen meglepetésekre, akkor szimlinkekkel termethetsz rendet, pl:
ls -l /usr/local/etc/php.ini /usr/local/bin/php.ini /usr/local/lib/php.ini
-rw-r--r-- 1 root system 67184 Jan 12 16:40 /usr/local/etc/php.ini
lrwxrwxrwx 1 root system    14 Jun 19  2013 /usr/local/bin/php.ini -> ../etc/php.ini
lrwxrwxrwx 1 root system    14 Jun 19  2013 /usr/local/lib/php.ini -> ../etc/php.ini
Az első a valódi fájl, a másik kettő szimlink.
K: Off-topic: PHP-scriptemben jogosultsági problémát vélek látni, hogyan debuggoljam?
V: Ilyesféle függvényeket használhatsz: posix_getcwd posix_getuid, posix_getgid, stat. Példaprogram:
 <?php
    function printfilestat ($fname) {
        $st= stat ($fname);
        if (! $st) {
            printf ("\n%s: 'stat' failed\n", $fname);
            return;
        }
        $userdata= posix_getpwuid ($st['uid']);
        $groupdata= posix_getgrgid ($st['gid']);
        printf ("file '%s': owner=%d(%s) group=%d(%s) access=%o\n",
            $fname,
            $st['uid'], $userdata['name'],
            $st['gid'], $groupdata['name'],
            $st['mode']);
    }

    printf ("<PRE>\n");
    $uid= posix_getuid ();
    $userdata= posix_getpwuid ($uid);
    $gid= posix_getgid ();
    $groupdata= posix_getgrgid ($gid);
    $cwd= posix_getcwd ();

    printf ("posix_pwuid=%d(%s) posix_getgid=%d(%s)\n",
        $uid, $userdata['name'],
        $gid, $groupdata['name']);
    printf ("posix_getcwd=%s\n", $cwd);

    printfilestat ($cwd);
    printfilestat (__FILE__);
    printfilestat (dirname (__FILE__));

    printf ("</PRE>\n");
?>
Egy lehetséges kimenet:
posix_pwuid=33(www-data) posix_getgid=33(www-data)
posix_getcwd=/local/home/projects/public_html
file '/local/home/projects/public_html': owner=1000(projects) group=1000(devel) access=40755
file '/local/home/projects/phptest/web/access.php': owner=1000(projects) group=1000(devel) access=100755
file '/local/home/projects/phptest/web': owner=1000(projects) group=1000(devel) access=40755
K: Szeretném www-data felhasználóként tesztelni a scriptemet, hogyan tehetem meg?
V: Rendszergazdaként (root user) így válhatsz www-data felhasználóvá:
$ ... become root (sudo/su/etc) ...
# su -l www-data -s /bin/bash
$ echo '<?php print_r(posix_getpwuid(posix_getuid())); ?>' | php
Array
(
    [name] => www-data
    [passwd] => x
    [uid] => 34
    [gid] => 34
    [gecos] => httpd User
    [dir] => /usr/local/www
    [shell] => /sbin/nologin
)
— Perl —
K: Az alábbi hibaüzenetet kapom a Perltől, hogyan tudom elnyomni?
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LC_CTYPE = "hu_US.CP856",
    LANG = "C"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
V: Legjobb lenne, ha kinyomoznád, hogy miért nem sikerült beállítani a lokalizációt, mit kell telepíteni, vagy a locale-gen-t futtatni, stb.
Mindazonáltal van 'gyorsmegoldás' a hibaüzenet elnyomására:
export PERL_BADLANG=0
K: Mit jelent a Wide character in print hibaüzenet?
V: Egy stringet akartál egy stream-be írni, és ennek során az alábbi három dolog találkozott össze: a string utf8-as kódolású, a stream nem utf8-módú, és a karakter nem konvertálható a stream-hez rendelt kódolásban (ennek az alapértelmezése lehet pl. iso-8859-1, ekkor ez U+FF fölötti unikódú karaktert jelent, amilyen például a magyar őŐűŰ).
K: Hogyan lesz a stream utf8-módú, illetve hogyan lehet a kódolást beállítani?
V: Az open MODE paraméterében megadhatod a :utf8 vagy :encoding(kód) opciót. (Az :utf8 és :encoding(UTF-8) hatása nem egészen egyforma: olvasás esetén az utóbbi ellenőrzi is az input utf8-validságát.)
Van még a binmode, amivel már megnyitott fájlokat (pl STDIN, STDOUT, STDERR) tudsz átállítani; illetve az open pragma amivel a fájlnyitásokhoz globálisan adhatsz meg beállítást, illetve az előbb felsorolt STDxxx fájlokat is átállíthatod, pl.:
use open ':std', IO=>':encoding(UTF-8)'
K: Úgy tűnik nekem, hogy a LC_CTYPE-ot nem veszi figyelembe, tudok tenni valamit ezügyben?
V: Ilyesmit lehetne próbálni:
my $lc_ctype= (split '\.', $ENV{'LC_CTYPE'})[-1];
open my $outfile, ">:encoding($lc_ctype)";
K: És mit jelent a use utf8;?
V: Azt, hogy maga a forrásprogram (vagyis a Perl script) utf8-ban értendő. Ennek az ellenkezője a no utf8; ami azt jelenti, hogy valamilyen 8-bites kódolásban van. Ezek hatása a fájl vagy a tartalmazó blokk végéig tart.
— Python —
K: Python3 forrásprogramban használhatok ékezetes betűket?
V: Igen, ha az első két sor valamelyik tartalmazza a használt kódolást, valahogy így:
#!/usr/local/bin/python3
# -*- coding: UTF-8 -*-
K: Milyen \-szekvenciák használhatók Python3-ban?
V: Használható a \x12, valamint a \u1234 (itt surrogate pair nem lehet) és \U12345678. Példa:
print('\u00e1rv\u00edzt\u0171r\u0151 t\u00fck\u00f6rf\u00far\u00f3g\u00e9p')
print('hamburger: \U0001f354');
árvíztűrő tükörfúrógép
hamburger: 🍔
K: Milyen kódolásban fog ez kiíródni?
V: Unixon a LC_CTYPE-nak megfelelően, Windowsban a default ANSI charset szerint. (A \x12-szekvenciát ISO-8859-1-szerint értelmezi, a 'coding'-tól függetlenül.) Megjegyzés: ha olyan karaktert írnánk ki, amely nem ábrázolható a kimeneti kódolásban, vagy ha a forrásprogram kódolása nem azonos a coding-ban megadottal, akkor hibaüzenetet vagy hibás eredményt kapunk.
K: A chr függvény paramétere milyen kódolás szerint értendő?
V: Unicode, függetlenül 'coding'-tól, pl.:
chr(0xf5)='õ'
chr(0xfb)='û'
chr(0x151)='ő'
chr(0x171)='ű'
K: Az ord függvény kimenete milyen kódolás szerint értendő?
V: Unicode, függetlenül 'coding'-tól, pl.:
ord('õ')=0xf5
ord('û')=0xfb
ord('ő')=0x151
ord('ű')=0x171
— Java —
K: Hogy tudok Javában String és byte-vector között konvertálni?
V: A String egyik konstruktora illetve a getBytes metódus szolgál erre.
K: Ha jól látom, vannak olyan változatok is, amelyeknek nem kell charsetName paraméter. Azok mire jók?
V: Hogy kibabrálhassál magaddal, illetve hogy platformfüggő legyen a működés (lásd a file.encoding beállítást).
K: Mindesetre, ha oda-vissza elvégzem a konverziót, akkor az eredetit kapom vissza, ugye?
V: Kivéve, ha nem. Pl. egybájtos kódolás esetén az "ôõő"-ből vagy "ôõ?" lesz, vagy "ô?ő". Vagy akár "???", szerencse kérdése.
K: És az igaz, hogy a 16-bites char típusban minden unikód elfér?
V: Hát tulajdonképpen nem, de az int típusban igen, illetve char-tömbben, vagy String-ben, UTF16 kódolással.
K: Vagyis szükség esetén 'helyettesítő párok' (magyarul 'surrogate pairs') használatával?
V: Igen, például a kedvenc hamburgerünket így tárolhatjuk String-ként: "\ud83c\udf54"
K: Ha Javában textfájlokat akarok írni/olvasni, a fájl-tartalom milyen kódolás szerint fog előállni/értelmeződni?
V: Valamilyen alapértelmezés / globális beállítás fog érvényesülni (lásd ezt a pontot is). Vagy használhatsz olyan metódusokat (pontosabban konstruktorokat), amiknek paramétere a karakterkészlet neve, pl:
  InputStreamReader (InputStream in, String charsetName)
  OutputStreamWriter (OutputStream out, String charsetName)
  PrintStream (File file, String csn)
K: JNI esetén hogyan férhetek hozzá egy String tartalmához?
V: Három lehetőséget látok: K: Ebből a 'módosított' részt nem értem pontosan...
V: A 'surrogate pair' elemeit külön-külön alakítja hárombájtos szekvenciáva, továbbá a nullás kódú karakterből C080 szekvenciát csinál, például "&#x1f354;&#0;" ilyen lesz módosított UTF-8-ban: ED-A0-BC—ED-BD-94—C0-80 (Közönséges UTF-8-ban ilyen: F0-9F-8D-94—00). Bővebben lásd itt: wiki: Modified UTF-8
K: A javac fordítóprogramnak kell tudnia, hogy a forrásprogram milyen kódolásban készült? És hogyan mondhatom meg neki?
V: Igen, a -encoding paraméterrel; ha nem adod meg, akkor valamilyen alapértelmezés jut érvényre, ami a konkrét esetben vagy jó, vagy nem. Az UTF-8 általában jó választás Java forrásprogramokhoz, de BOM ne legyen a fájl elején!
K: Szóval a Java forrásprogramok string-konstansaiban használhatok \uXXXX szekvenciákat. És string-konstansokon kívül is használhatom őket?
V: Igen, bárhol a forrásprogramban; ezeknek az értelmezése minden más fordítási lépés előtt történik, ami váratlan következményekhez is vezethet; íme egy egyszerű példa:
public class hellocomment {
    public static void main (String args[]) {
        // Where is the code? \u000d System.out.println ("Hello, comment\u0022);
    }
}
Itt a \u000d sorvégejelnek számít, tehát ami mögötte van, az nem megjegyzés; a \u0022 pedig a "macskaköröm", ami lezárja a stringet.
K: IBM MQS-t használnék Javából. Igaz, hogy az egyes üzenetek karakterkódolását külön-külön lehet beállítani/lekérdezni?
V: Igen, erre való a com.ibm.mq.MQMessage.characterSet mező. Persze egyedi IBM-es kódokat kell használni, pl:
	  37	ebcdic/ibm/latin1-compatible
	 850	cp850
	 852	cp852
	 819	iso-8859-1
	 912	iso-8859-2
	1208	utf-8
K: Milyen műveleteket használhatok bináris üzenetekhez?
V: Itt van rögtön a write, a getDataLength és a readFully. (Ezek bájttömbökkel dolgoznak, tehát semmiféle konverzió nem történik.)
K: Milyen műveleteket használhatok karakteres üzenetekhez?
V: Íráshoz van egy writeString művelet; olvasáshoz a readStringOfByteLength metódust ajánlom, a getDataLength metódussal kombinálva (ezek gondoskodnak a karakterkonverzióról (lásd fentebb a characterSet mezőt).
Ha esetleg olyan ősrégi kliensed van, amelyben még csak sima readString művelet van, akkor a multibyte-os kódolásokhoz valamilyen helyettesítő megoldást kell tákolni, pl.:
        message.seek(0);    /* álljon az üzenet elejére */
        int blen= message.getDataLength ();
        String s;

        if (message.characterSet==1208) { /* csak egy multibyte-os kódolást kezelünk, az UTF8-at */
            byte [] binmsg = new byte [blen];
            message.readFully (binmsg);

            s = new String (binmsg, "UTF-8");
        } else {
            s = message.readString (blen);
        }
        return s;
K: Java programomban SimpleDateFormat-ot használok. Egyes értékek (nap és hónap neve, am/pm jelző) lokalizáció-függőek, ezek működése mitől függ?
V: Tapasztalataim szerint Unixban a LC_CTYPE-tól, Windows-on a -Duser.language-tól.
K: A JAXB által létrehozott XML milyen encoding-ban keletkezik?
V: Alapértelmezésben UTF-8, de a javax.xml.bind.Marshaller.setProperty metódussal másra is be lehet állítani, pl.:
    marshaller.setProperty ("jaxb.encoding", "ISO-8859-2");
— SQL-injection —
K: Mi is az Sql-injection lényege?
V: Legvilágosabban ezen az ábrán mutatják be: http://xkcd.com/327/
K: Nem értem, miért okozna gondot ez a név?
V: Akkor nézzük meg, hogyan működött a program:
Ezt akarta a programozó:
INSERT INTO students (name) VALUES ('<insertnamehere>');
De ez lett belőle:
INSERT INTO students (name) VALUES ('Robert'); DROP TABLE students; -- ');
K: Azannya! De biztos az, hogy ilyen támadás minden adatbáziskezelőben és minden kontextusban lehetséges?
V: Természetesen nem: előfordulhat, hogy a te esetedben csupán hibaüzenetet, hibás működést lehet így előidézni, nem pedig teljes adattörlést. Akarsz kockáztatni?
K: Jó, persze, nem, de azért azt megkérdezem, hogy miért csak SQL-injection van, miért nincs például HTML-injection, PHP-injection, shell-script-injection, és a többi?
V: Megnyugtatlak: ezek mind előfordulhatnak, és mind ellen védekezni kell. Alapvetően két gond van:
1. A hibás (vagy rossz-szándékú) adat olyan karaktereket tartalmaz, amiknek nem szabadna ott lenniük.
2. Az adat teljesen legálisan tartalmaz olyan karaktereket, amik megzavarhatják pl. az SQL-értelmezőt.
K: Akkor már értem, mi a baj. És mi lenne a megoldás?
V: Nos, ha például előre tudjuk, hogy mik a megengedhető karakterek, akkor ellenőriznünk kell az input-ot. Egy példa PHP-hez:
/* csak magyar kis- és nagybetűk, valamint számjegyek (és nem üres!) */
function Test ($s)
{
    $pattern= '/^[0-9a-záäéíóöőúüűA-ZÁÄÉÍÓÖÚÜŰ]+$/';
    printf ("check(%s)=%d\n", $s, preg_match ($pattern, $s));
}
Egy pedig Javához:
/* csak magyar kis- és nagybetűk, valamint számjegyek (és nem üres!) */
static void Test1 (String s) {
    boolean fOk= s.matches ("^[0-9a-záäéíóöőúüűA-ZÁÄÉÍÓÖÚÜŰ]+$");

    System.out.println ("Check ('" + s + "'): " + fOk);
}
K: És ha az input legálisan is tartalmazhat mindenféle jeleket?
V: Az egyik legjobb lehetőség az adatok és a kódok elválasztása; SQL-esetében a bind változók valók erre (lásd a következő fejezetben). Ha erre nincs lehetőség, a helyzettől függő módszereket kell használni ahhoz, hogy 'veszélyes' karaktereket tartalmazó adatot is jól kezeljünk.

1. példa: Oracle esetében a string-literál belsejében lévő aposztrófákat meg kell duplázni:
select 'Ezt mondta: ''hello''' AS idezet from dual;
IDEZET
-------------------
Ezt mondta: 'hello'
Ha pl. Javában alkotunk, ilyesmit írhatunk:
String ora_sql = "UPDATE tabla SET mezo='"+param.replaceAll("'", "''")+"'";
PHP-s példa:
$ora_sql = sprintf ("UPDATE tabla SET mezo='%s' WHERE ...",
    str_replace ("'", "''", $param));

2. példa: MySql esetében (általában) a \backslash használható escape-characterként a string-literálokban (PHP esetén lásd az addslashes illetve mysql(i)_real_escape_string függvényeket):
select 'Ezt mondta: \'hello\'' AS idezet;
Megj: Egyes egzotikus két- vagy több-bájtos kódolások esetén (az UTF8 nem ilyen) a \backslash része lehet egy bájt-szekvenciának, tehát ilyenkor nem jó az addslashes. Mivel ezek a szekvenciák a magyar nyelvhez nem használatosak, nem kell különösebben aggódnunk; mindenesetre arra ügyeljünk, hogy a(z esetleg rossz-szándékú) felhasználó ne avatkozhasson bele a SET NAMES-be.

3. példa: Ha HTML-be akarunk ilyen stringet illeszteni, használjuk az &-szekvenciákat – PHP esetén erre való a htmlspecialchars függvény (lásd ezt a pontot is!):
    $s= '<B>veszélyes szöveg <script>benne gonosz script</script></i>';
    print htmlspecialchars ($s, ENT_QUOTES, 'ISO-8859-1');
Java esetén különféle külső eszközök használhatók, de ha épp egyik sincs a kezünk ügyében, akár kézi erővel is alkothatunk valamit:
static String htmlescape (String s) {
    String sout=
        s.replaceAll ("&", "&amp;")
         .replaceAll ("<", "&lt;")
         .replaceAll (">", "&gt;")
         .replaceAll ("\"","&quot;")
         .replaceAll ("\'","&#x27;");
    return sout;
}
Megj: Például ezt a programrészt is át kellett alakítani ahhoz, hogy a HTML-ben jól jelenjen meg.
Ugyanez JavaScript-ben ilyesmi lenne:
function htmlescape (s) {
    var sret=
       s.replace (/&/g, '&amp;')
	.replace (/</g, '&lt;')
	.replace (/>/g, '&gt;')
	.replace (/\"/g,'&quot;')
	.replace (/\'/g,'&#x27;');
    return sret;
}

4. példa: PHP-ből akarunk shell-scriptet hívni. (Nagyon problémás terület, szívesebben ajánlanám az environment változók használatát!):
    $gyanus= "\"; rm -rf /fontos/dir/*; echo \" $(rm /important/)";
    $cmd= sprintf ('echo "Naplósor: %s" >>Naplo',
	addcslashes ($gyanus, '"$`\\'));
    system ($cmd);

5. példa: PHP és JavaScript között akarunk adatot cserélni. Erre való a JSON tehcnológia, pl.:
{"veznev": "árvíztűrő",
 "utonevek": ["els\u0151","m\u00e1sodik"]}
Komplett tömböket és struktúrákat is kezel, az ékezetes betűket UTF-8-ban vagy \u szekvenciákkal adhatjuk meg. Az egyetlen problémás pont az, ha a HTML-be ágyazott JavaScript-ben véletlenül a </script> string fordul elő, ugyanis a böngésző azt a script lezárásnak tekinti. A defenzív megoldás az, ha minden / jelet "escape-elve", \/ formában adunk meg.

6. példa: CSV fájlt akarunk előállítani/elemezni. Ugyebár ennél semmi sem egyszerűbb, de azért gondoljunk a következőkre:
(1) ha egy mezőben elválasztójel (magyar beállítás esetén vesszőspont), sorvége, vagy idézőjel (rendszerint "macskaköröm") van, akkor a mezőt kötelező idézőjelek közé tenni, egyébként csak szabad idézőjelek közé tenni.
(2) ha egy mező idézőjelek között van, akkor a benne előforduló idézőjeleket meg kell duplázni.

7. példa: shell-ben írt CGI-program fájlneveken megy végig, és <img src="fájlnév"> tagokat állít elő. Nincs semmi gond, amíg egy haxor létre nem hoz egy abc"><h1>Rossz az oldalad.jpg nevű fájlt (ami teljesen legális fájlnév Unixban!), és ezzel elcsúfítja a kimenetet. Megoldási lehetőség a shell scriptben:
for i in *.jpg; do 
    i2="$(printf '%s' "$i" | sed 's/\"/\&quot;/g')"
    printf '<img src="%s">\n' "$i2"
done
K: Erről jut eszembe: esetleg ilyesmi okból szüntették meg PHP-ben a register_globals intézményét?
V: Bizony ám! A register_globals okozta gondot nevezhetjük akár PHP-injection-nak is.
K: Ugye az UTF-8-nak nincs semmi köze ehhez, vagy más biztonsági kérdésekhez?
V: Semmi, kivéve azt apróságot, hogy nem szabad elfogadni olyan UTF-8 kódolású inputot, amelyben előfordul olyan karakter, ami nem a lehető legrövidebb módon van kódolva. Például a 27 hexkódú 'aposztrófát' lehetne hosszabban is kódolni (C0A7, E0C0A7 vagy F0C0C0A7), és ezzel esetleg megkerülni az ellenőrző programrészeket, de a szabvány szerint az ilyen szekvenciákat érvénytelennek kell tekinteni.
— Bind-változók —
K: Mi is az a bind-változó?
V: Részletesen lásd itt: wiki:Prepared statement, a lényeg az, hogy az adatok nincsenek az SQL-utasításba beleágyazva, hanem külön mennek át. Példa:
volt: INSERT INTO t_login VALUES ('userid', 'jelszó')
lett: INSERT INTO t_login VALUES (?, ?)
K: De így külön hívások kellenek az adatok megadásához, vagyis a program bonyolultabb és lassabb lesz!
V: Valóban bonyolultabb, mivel a végrehajtás nem egy, hanem három részből áll: elemzés (parse vagy prepare), értékek megadása (binding) és végrehajtás (execute); viszont adott esetben lehet, hogy a művelet nem lassabb lesz, hanem gyorsabb.
K: Vajon mitől?!
V: Attól, hogy így nagy az esélye annak, hogy a szerverhez többször egymás után ugyanaz az SQL-utasítás érkezik (az utasításba beépített értékek esetén ez nem valószínű). Ennek az az előnye, hogy a szerver (amely gyorstárazza a legutóbbi utasításokat), felismeri az utasítást, és így a munka egyik időigényes részét, az elemzést megspórolja.
K: PHP és MySql esetén használhatók bind változók?
V: A mysqli modul használatával. A PHP-ben használható egyéb adatbáziskezelőről itt olvashatsz: PHP: Database Extensions
K: Ilyen bind-változók használhatók más kontextusban is? Például PHP-ből shell-hívásakor?
V: A környezeti változók (environment variables) használhatók erre a célra, pl:
<?php
/* felhasználótól jövő megbízhatatlan input */
    $s = '"; echo én vagyok a haxor és törlök; rm legfontosabb_file #';

/* veszélyes megoldás */
    $cmd= sprintf ('echo "Test#1 %s" >>kedvesnaplom', $s);
    system ($cmd);

/* biztonságos megoldás */
    putenv ('param1='.$s);
    $cmd= 'printf -- \'Test#2 %s\\n\' "$param1" >>kedvesnaplom';
    system ($cmd);
?>
Az utóbbi helyzetben a param1-ben lévő idézőjelek, joker-karakterek, \-szekvenciák stb. nem jutnak érvényre.
Ugyanez Perl-ben:
$NAME="John Doe'; pwd -P; echo 'I escaped your quotes";

system ("echo Username='$NAME'"); # Haxor wins

$ENV{'param_1'}=$NAME;
system ("echo Username=\"\$param_1\""); # Haxor loses
K: Ha már így feljött a shell-hívása, van-e még valamilyen fontos szabály, amit tudnom kell?
V: Igen: hogy ha csak lehet, kerüld el, mert nagyon lassú. Nagyon sok mindenre van PHP-beli megoldás, ne légy rest, használd a php.net keresőjét.
K: Shell-hívásról szólva, pl. C-nyelv esetén is használhatunk így environment változókat?
V: Igen, pl. a system és popen függvények esetében; a változók beállítására és törlésére használhatjuk a setenv és unsetenv függvényeket:
setenv ("param1", dangerous_value, 1);
system ("printf -- '%s\\n' \"$param1\" >>naplo");
unsetenv ("param1");
Kevésbé korszerű esetben mindkettő a putenv függvénnyel történhet:
char env_tmp[64];

sprintf (env_tmp, "param1=%.*s", (int)(sizeof env_tmp -8), gyanus_input);
putenv (env_tmp);
system ("printf -- '%s\\n' \"$param1\" >>naplo");
putenv ("param1=");
— Miegymás —

K: Ha a böngésző az ékezetes karakter helyett egy olyan szekvenciát küld, hogy &#unikód; az mi a manót jelent?
V: Azt, hogy a felhasználó olyan karaktert írt (pasztázott) az input-mezőbe, ami nincs benne az oldalad által használt kódban (illetve a <FORM> tagban megadott accept-charsetben). Például, ha latin2-t állítasz be, akkor a hullámos Õ betű helyett ilyen szekvenciát (&#213;) küld a Firefox.

K: Szóval ez még böngészőfüggő is? Mi lehet a megoldás?
V: Mondjuk az UTF-8 használata, amit persze kiegészíthetsz azzal, hogy szűröd a beérkezett inputot: pl. amit az iconv nem tud konvertálni a neked tetsző kódkészletre (windows-1250, mondjuk), azt elutasítod.

K: Lehetséges, hogy az SAP program egyedi számokat rendel a különféle kódolásokhoz?
V: Természetesen, anélkül nem vesznek komolyan egy enterprise rendszert. Külön bónusz, hogy teljes lista nem érhető el, néhány érték az internetről összevadászva:
1100 ISO-8859-1
1140 ISO-8859-1
1160 Windows-1252
1401 ISO-8859-2
1404 Windows-1250
4102 UTF-16BE
4103 UTF-16LE
4110 UTF-8
— WinDos —
K: A DOS-ablakban nem jól jelennek meg az ékezetes betűim...
V: A DOS-ablakról azt kell tudnod, hogy ott a CP852 nevű kódolás érvényesül, ha a text-editorod nem tudna bele/belőle konvertálni, az iconvra mindig számíthatsz:
iconv -f latin2 -t cp852 <winfile >dosfile
iconv -f cp852 -t utf-8 <dosfile >utf8file
K: Nem lehet átállítani másra, pl win-1250-re?
V: De lehet, két dolog kell hozzá: az egyik, hogy a karakterkészlet ne a Raster Fonts legyen, hanem a Lucida Console (Tulajdonságok/Font/Font), a másik a CHCP 1250 parancs futtatása. A CMD.EXE esetében a registry-ben megadható, hogy ezt automatikusan futtassa: HKLM\SOFTWARE\Microsoft\Command Processor\AutoRun-ba: CHCP 1250 >NUL Egy másik lehetőség, hogy a saját programodból hívod meg: system ("CHCP 1250");
K: És ha nem globálisan akarom beállítani, hanem úgy, hogy csak a saját programomra vonatkozzon?
V: Ha a programod egy Windows-alkalmazás, akkor az alábbi kódrészlet segít:
SetConsoleCP (1250);
SetConsoleOutputCP (1250);
Egyéb esetben ezzel próbálkozhatsz:
system ("CHCP 1250");
Kiegészítés: A fenti SetConsoleCP és SetConsoleOutputCP és függvények lekérdező párja a GetConsoleCP és GetConsoleOutputCP.
K: Egyéb lehetőségek?
V: Például megteheted, hogy eleve DOS-os szövegszerkesztőben írod a programodat, amilyen pl. a NCEDIT. További lehetőség a konverzió, például a Windows beépített függvényeivel: CharToOem CharToOemBuff OemToChar OemToCharBuff. Vegyük észre, hogy ezeknél sem a forrás sem a cél karakterkészletet nem kell megadni, azt a Windows magától állapítja meg, a Területi beállítások (és talán a billentyűzetkiosztás(?)) alapján. Lásd még: GetACP GetOEMCP Code Page Identifiers.
K: A setlocale függvényt hogyan használjam, hogy ezzel összhangban legyen (és jól működjenek az isalpha- és toupper-szerű makrók)?
Itt a LC_CTYPE beállítása számít, több lehetőség van, pl.:
    setlocale (LC_CTYPE, ".1250");	/* fixen windows-1250 */
    setlocale (LC_CTYPE, ".852");	/* fixen IBM-852 */
    setlocale (LC_CTYPE, "");		/* a gép default kódolása, valószínűleg azonos a következővel: */
    setlocale (LC_CTYPE, ".ACP");	/* a gép default "ANSI" kódolása */
    setlocale (LC_CTYPE, ".OCP");	/* a gép default "OEM" kódolása */
    setlocale (LC_CTYPE, "hu-HU");	/* alapértelmezett magyar kódolás, valószínűleg windows-1250
					   kieg: ez egy másik Windows verzióban nem működött, ezért
					   nem javaslom a használatát */
    setlocale (LC_CTYPE, "hun");	/* alapértelmezett magyar kódolás, valószínűleg windows-1250 */
Megj: Ezt persze a fenti CHCP-vel (és a programíráskor használt kódkészlettel) összhangban érdemes beállítani; ne felejtsük el, hogy a LC_ALL magában foglalja a LC_CTYPE-ot is, pl.:
    setlocale (LC_ALL, "Hungarian_Hungary.1250");	/* Windows1250-hez */
    setlocale (LC_ALL, "Hungarian_Hungary.852");	/* CP-852-höz */
K: Milyen környezeti változókkal lehet befolyásolni a setlocale működését Windows-ban?
V: Ha a kísérleteim nem csalnak, akkor semmilyenekkel, tehát ha a második paraméter a default-ot jelentű üres string, akkor csak a registry-ből tájékozódik, nem környezeti változókból.
K: UTF8-at is lehet használni a DOS-ablakban?
V: Igen, a beállítás: system ("CHCP 65001");
K: Ez így biztos jó lesz?
V: Nem biztos. Nem teszteltem alaposan, de első kísérletre úgy tűnik, hogy minden billentyűzetről olvasó művelet (pl fgets, getline), egységesen nem tud beolvasni ékezetes betűt tartalmazó szöveget.
K: Más baj nincs vele?
V: Egyes régi Windows-ok (pl. XP) a CHCP 65001-et azzal nyugtázzák, hogy az illető CMD.EXE példány képtelenné válik batch-ek (.BAT, .CMD) futtatására. (Ha indítunk egy batch-et, hibaüzenet nem jön, de a batch sem hajtódik végre.) Például a TortoiseCVS CVS.EXE programja csinál ilyet.
K: A Command Prompt-ban futtatott java ékezetei sem egészen jók... vagy egy magyar betű sem jó, vagy csak az ő/ű nem jó.
V: Próbálkozz meg az alábbiak valamelyikével (az első kettő nagyjából ugyanaz, akkor használhatóak, ha volt CHCP 1250 előtte, a harmadik akkor, ha az alapértelmezett CHCP 852 van érvényben, az utolsó pedig az UTF8 (CHCP 65001) esetére):
java -Dfile.encoding=iso-8859-2 classname
java -Dfile.encoding=windows-1250 classname
java -Dfile.encoding=cp852 classname
java -Dfile.encoding=utf-8 classname
Megj.: természetesen ez a file.encoding opció nem csak Windows-ban használható.
K: Jól látom, hogy Windows-ban szimlinket sem tudok csinálni?
V: NTFS fájlrendszeren tudsz könyvtárra mutató symlinket csinálni, a junction nevű programmal. Példa a használatára:
 JUNCTION C:\jdk "C:\Program Files\Java\jdk1.6.0_04"
 SET JAVA_HOME=C:\jdk
 PATH %JAVA_HOME%\bin;%PATH%
Ha ezután új verziót telepítünk, csak a szimlinket kell átirányítanunk rá, minden más maradhat változatlan.
Megj: Újabb Windows-okon van erre beépített parancs is, a mklink, az nem csak könyvtárra, hanem fájlra mutató szimlinket is tud csinálni.
K: Windows-ról szólva, a billentyűk kódjairól (VK_***) hol tudok tájékozódni?
V: Itt: msdn: Virtual-Key Codes
K: Pont a magyar billentyűzet magyar betűit nem látom ott...
V: Saját méréseim a következőt mutatják:
Bill Kód  Név
 É   BA   VK_OEM_1
 Ó   BB   VK_OEM_PLUS
 Ü   BF   VK_OEM_2
 Ö   C0   VK_OEM_3
 Ő   DB   VK_OEM_4
 Ű   DC   VK_OEM_5
 Ú   DD   VK_OEM_6
 Á   DE   VK_OEM_7
 Í   E2   VK_OEM_102
K: És a WM_CHAR üzenetnél milyen kódot kapok a wParam-ban? A Windows aktuális ANSI kódját (pl windows-1250), vagy unikódot?
V: A RegisterClass milyenségén múlik: ha az RegisterClassW volt, akkor unikód, egyébként ANSI.
Megj: Az ablaknak ezt a tulajdonságát le is lehet kérdezni az IsWindowUnicode függvénnyel.
K: Van Windows-ban egy olyan, hogy Vezérlőpult / Terület és nyelv / Felügyelet / Unicode szabványt nem támogató programok nyelve. Ez pontosan mit szabályoz?
V: Azt nem tudom, de valószínűleg nem lesz baj belőle, ha magyar (Magyarország)-ra állítod. Vigyázz, ez globális beállítás, tehát a gépen minden felhasználóra és minden programra vonatkozik.
K: Ennek van köze az alábbi registry-entrykhez?
HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP
HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\OEMCP
V: Valószínűleg van.
K: Ugyanott a Vezérlőpulton (egyes Windows10 verziókban) van egy olyan rész is, hogy
Béta: Unicode UTF-8 használata a globális nyelvi támogatáshoz
Ez vajon mit csinál?
V: Egyelőre annyit vettem észre, hogy ezt beállítva a setlocale függvényben használható lesz az UTF8-at jelentő 65001 érték, pl:
setlocale(LC_ALL, "hungarian_Hungary.65001");
K: A SetThreadLocale függvény pontosan mit szabályoz?
V: Hát, szinte biztos, hogy valamire valamilyen hatása van, kivéve, ha nincs. Ha úgy érzed, hogy használni akarod, akkor ebből a táblázatból válaszd ki a magyar beállításokat jelentő 1038 (0x040e) értéket. Ezt a számot így is előállíthatjuk:
    MAKELCID
	(MAKELANGID (LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY),
	 SORT_HUNGARIAN_DEFAULT)
K: Windows esetén van eszköz saját billentyűkiosztás létrehozására?
V: A Microsoft Keyboard Layout Creator (MSKLC) nevű program való erre, ingyen letölthető a Microsoft-tól; vannak gyenge pontjai, például kell neki a .NET framework valamelyik régi verziója, valamint hogy bizonyos képernyőfelbontásoknál nem (jól) működik.
K: Ezzel tudom például a NumLock billentyűt letiltani?
V: Azt pont nem, de ügyes registry-haxolással ez is megoldható, lásd pl. itt:
; bekapcsoláskor NumLock=on
[HKEY_USERS\.DEFAULT\Control Panel\Keyboard]
"InitialKeyboardIndicators"="2147483650"

; NumLock billentyű letiltása:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,00,00,45,00,00,00,00,00
K: (Windows-hoz érintőlegesen kapcsolódó kérdés) A programom CSV-fájlt állít elő. Tudom befolyásolni, hogy Excel-ben hogyan jelenjen meg a tartalma?
V: Valamennyire igen, de vedd figyelmebe, hogy ezek nem valamilyen szabványon alapulnak (pl RFC4180), tehát nem garantálható, hogy minden kontextusban működnek.
• Ha van a fájl legelején BOM, akkor az Excel a tartalmat UTF8-ként értelmezni, egyébként a default ANSI kódolás (pl. Windows-1250) szerint.
• Az elválasztókaraktert (tipikusan vessző vagy vesszőpont) megadhatod a fájl elején egy külön sorban, pl:
sep=;
• Az egyes mezőket dátumként vagy számként értelmező mesterséges intelligencia semlegesíthető, ha időzőjelek közé tesszük az értéket, és egyenlőségjelet teszünk elé, pl.:
head: OpenSSL;OpenSSH
volt: 3.1.1; 8.7        -- ebből lehet pl. egy dátum és egy szám
lett: ="3.1.1"; ="8.7"  -- ez megmarad
K: Excel-ben a KARAKTER és KÓD (eredetileg CHAR és CODE) függvények milyen kódolás szerint működnek?
V: A kísérletek szerint Default ANSI kódolásban; a KÓD függvény az abban nem található karakterekre egységesen a kérdőjel kódját (63) adja. Újabban van már UNIKARAKTER (erdetileg UNICHAR) és UNICODE függvény is. Példa magyar Excel-ből (figyeljünk a magyar Ő és a hullámos Õ közötti külünbségre):
KARAKTER(213)=   Ő   KÓD("Ő")=213  UNICODE("Ő")= 336
UNIKARAKTER(213)=Õ   KÓD("Õ")= 63  UNICODE("Õ")= 213
UNIKARAKTER(336)=Ő   KÓD("Я")= 63  UNICODE("Я")=1071
K: És az Excelen belüli VBA-ban?
V: A fentiekkel összehasonlítható függvények az alábbiak:
asc(char) ANSI karakterkód (ha a karakter benne van a 'default ANSI'-ban, ha nincs, az eredmény meglepő lehet, pl. Asc('Õ')=Asc('O'))
ascW(char) unikód (bármilyen karakteré)
char(ansikód) kód alapján karakter (default ANSI)
charW(unikód) unikód alapján karakter
Valamint, ha jól vélem látni, az editor-ablakban eleve csak Default ANSI karakterek használhatók.
— Linux —
K: Gondolom linuxban nincs ilyen probléma...
V: Ott is gondot okozhat, ha nem tudod, hogy a terminálon milyen karakterkódolás van érvényben (a leggyakoribb persze ott is a latin2 és az utf8). Az alábbiak valamelyike segíthet eligazodni:
locale | grep LC_CTYPE
echo ${LC_ALL-${LC_CTYPE-$LANG}}
echo -n 'ő' | od -tx1 # f5->latin2, c591->utf8
K: Csak a LC_CTYPE beállítása fontos az ékezetes betűk szempontjából?
V: Azért ez sem egészen biztos: előfordulhat, hogy ha a lokalizáció valamelyik aspektusa (például a LC_TIME) nem jó, akkor a setlocale(3) függvény is hibával tér vissza, amitől egyik-másik program úgy dönthet, hogy el sem indul, vagy pedig hétbites ASCII módban működik. (Ez utóbbit pl. egy Midnight Commanderrel idéztem elő.)
K: Említetted a LC_TIME-ot: ennél is számít, hogy hu_HU.ISO-8859-2 vagy hu_HU.UTF-8 van-e benne?
V: Bizony számít: amikor egy program (pl. a ls) a hónapok nevét akarja kiírni, pl a jún rövidítés latin2-ben három bájt (6a fa 6e), utf8-ban négy (6a c3 ba 6e), ezt a LC_TIME határozza meg.
Példa:
$ LC_TIME=hu_HU.ISO-8859-2 date -d 2019-08-19 '+%A' | xxd
       0: 68 e9 74 66  f5 0a                                  h.tf.

$ LC_TIME=hu_HU.UTF-8      date -d 2019-08-19 '+%A' | xxd
       0: 68 c3 a9 74  66 c5 91 0a                            h..tf..
K: A linux virtuális termináljain (Alt+F1...Fn) mi van, UTF-8, vagy 8-bites kódolás (pl ISO-8859-2), vagy szabályozható?
V: Szabályozható, programból az ioctl (KDSKBMODE, K_XLATE/K_UNICODE) rendszerhívással (az első a 8-bites);
shell-ből a kbd_mode -a/-u vagy az unicode_stop/unicode_start paranccsal;
rendszerinduláskor a vt.default_utf8=0/1 kernelparaméterekkel (lásd a lilo/grub append parancsát).
K: És, gondolom, a LC_CTYPE változót is ezzel összhangban kell beállítanom... Ugye azt teljesen szabadon állíthatom be?
V: Teljesen szabadon a localedef --list-archive által felsoroltak közül érdemes választanod; ha az nem elég, bővitsd a /etc/locale.gen listát, és futtasd a locale-gen-t (mindez disztribúciófüggő lehet, olvasd el a locale-gen manuálját).
K: De ha én mondjuk IBM852-es vagy Windows-1250-es kódolást szeretnék használni Linuxon, akkor megsemmisül a világegyetem, vagy ez is lehetséges?
V: Méréseim szerint ez is lehetséges, ha vannak ilyen fájlok a /usr/share/i18n/charmaps könyvtárban (ez persze disztribúciófüggő lehet), pl.:
$ cat /etc/locale.conf
...
hu_HU        ISO-8859-2
hu_HU.IBM852 IBM852
hu_HU.CP1250 CP1250
hu_HU.UTF-8  UTF-8
...
# locale-gen
Generating locales (this might take a while)...
...
  hu_HU.ISO-8859-2... done
  hu_HU.IBM852... done
  hu_HU.CP1250... done
  hu_HU.UTF-8... done
...
Generation complete.
$  LC_ALL=hu_HU.IBM852 mc # nézzük meg a HELP-et (F1)
K: Ha a rendszeremben (pl. Centos) nincs locale-gen, akkor mit tehetek?
V: A locale-gen csak egy script, a tényleges munkát a localedef végzi, például ebből a sorból
hu_HU.win-1250 CP1250
ez a localedef hívás lesz:
localdef -i hu_HU -c -f CP1250 -A /usr/share/locale/locale.alias hu_HU.win-1250
#   -i inputfile   (pl. /usr/share/i18n/locales/hu_HU)
#   -c force (kisebb hibákon lépjen át)
#   -f charmapfile (pl. /usr/share/i18n/charmaps/CP1252.gz)
#   -A aliasfile
#   a végén a teljes név
Tehát ha nincs locale-gen, akkor a localedef közvetlen hívásával próbálkozhatsz.
K: És az emulált terminálokon (xterm és vidéke)?
V: Az emulátor az indulásakor a LC_CTYPE alapján dönti el, hogy egybájtos vagy unikódos módban működjön-e. Valahogy így lehet kipróbálni:
LC_CTYPE=hu_HU.ISO-8859-2 xterm -e sh -c 'showkey -a' &
LC_CTYPE=hu_HU.UTF-8      xterm -e sh -c 'showkey -a' &
A magyar ékezetes betűk billentyűit próbájuk ki, látni fogjuk a különbséget.
K: Mit csinál az emulátor, ha a szervertől kapott adat nem olyan kódolású, mint amit elvár?
V: Ha egybájtos üzemmódban van, és a szervertől UTF8-at kap, akkor nincs semmi gond, csak a felhasználó látja, hogy baj van, például tűzvész helyett tűzvész (latin1) vagy tĹązvĂŠsz (latin2) jelenik meg.
Ha UTF8-módban a szervertől egybájtos kódolású adat érkezik, akkor az emulátor döntésén múlik, hogy mit tesz az érvénytelen karakterekkel: eldobja őket, vagy helyettesíti kérdőjellel (vagy más 'hibajelző' karakterrel), vagy esetleg segíteni akar és latin1-ként értelmezve megjeleníti az inputot. Ez utóbbi esetben a latin2-es tűzvész helyett tûzvész jelenik meg, amit a felhasználó esetleg észre sem vesz, vagyis nem szerez tudomást arról, hogy a kliens és a szerver beállításai nincsenek összhangban.
K: Az emulátort futás közben is át lehet állítani egyik üzemmódból a másikba?
V: Egyes emulátorok (pl. xterm) esetén az alábbi escape-szekvenciákkal:
    ESC % G	UTF8-mód
    ESC % @	egybájtos kódolás
K: A LC_CTYPE-ról szólva úgy látom, a különféle Unixok nem egészen értenek egyet abban, hogy az ISO-8859-2 és az ISO8859-2 közül melyik a jobb.
V: Én sem tudom, hogy melyik a jobb, csak azt, hogy a felhasználóknak gondot okozhat ez a kettősség, pl. ha távoli eléréssel (ssh) érkezik egyikből a másikba. Ilyesmit lehetne valamilyen 'profile' fájlba tenni:
# ISO-8859 => ISO8859 irány,
# a változók listája értelemszerűen bővítendő
for var in LANG LC_CTYPE LC_ALL; do
    eval "OLDVAL=\$$var"
    TMPVAL=$(echo "$OLDVAL" | sed 's/ISO-8859/ISO8859/')
    if [ "$TMPVAL" != "$OLDVAL" ]; then eval "$var='$TMPVAL'"; fi
done
K: Még így is kapok egy warning-ot a bash-tól...
K: Akkor keményebb eszközhöz kell nyúlni, a neve szimlink. Pl. AIX esetén:
ln -s en_US.ISO8859-1 /usr/lib/nls/loc/en_US.ISO-8859-1
ln -s hu_HU.ISO8859-2 /usr/lib/nls/loc/hu_HU.ISO-8859-2
Megj: Ez nem az előző helyett ajánlom, csak annak kiegészítéseképpen.
K: A mcedit-ben (illetve a mcview-ben) egyes ékezetes karakter rosszul jelennek meg, vagy ^A szekvencia látszik helyettük, mit tegyek ez ellen?
V: Az a terminál(emulátor)od fajtájától (utf8 vagy 8-bites), és a fájl kódolásától függ. (Mindenesetre a LC_CTYPE enviró a terminál beállításával (pl. PuTTY esetén ez a Translation funkció) összhangban kell legyen, különben garantált a hibás működés.)
• utf8-as terminálon a LC_CTYPE enviró legyen hu_HU.UTF-8 (vagy en_US.UTF-8 stb.), a mcedit Choose Codepage (ALT+c billentyű) beállításánál pedig a fájl tartalmának megfelelő kódolást válaszd.
• 8-bites terminálon a LC_CTYPE enviró legyen összhangban a terminál kódolásával (pl. hu_HU.ISO-8859-2 vagy fr_FR.CP1252), a Choose Codepage-nél pedig a fájl tartalma szerint vagy az UTF-8-at (c billentyű), vagy a megfelelő 8-bites kódolást válaszd.
Természetesen 8-bites terminálon semmiképp sem jelennek meg azok a karakterek, amelyek nincsenek benne a terminál kódkészletében (ilyenkor pontokat vagy ^A szekvenciákat jelenít meg az editor). Ha a fájl kódolása egyezik a termináléval (pl. mindkettő ISO-8859-2), akkor a < No translation > beállítást is használhatod).
Megj: A 4.8.20-as verzió előtt volt egy hiba, ami zavart okozott, amikor utf8-as fájlt szerkesztettünk 8-bites terminál(emulátor)ban.
K: Az stty -a kimenetében láttam egy iutf8 (vagy -iutf8) részt. Azt jelenti ez, hogy a kernel is követi, hogy UTF8-at használok-e, vagy sem? Ha igen, miért?
V: Igen, a kernel (legalábbis Linux esetén) tudja, hogy UTF8-at használsz, ennek akkor van jelentősége, amikor 'főzött' (cooked) módban használod a billentyűzetet. Ez egyszerűbben mondva azt jelenti, hogy az Enter megnyomásáig a felhasználói program nem kap semmilyen inputot, akkor viszont egyszerre az egész sort. A gépelés közben szerkesztésre használhatod (egyebek mellett) a BackSpace billentyűt, ez törli az utolsó karaktert. No ehhez a művelethez van szükség arra az információra, hogy egy karakter egy bájtot, vagy egy utf8-szekvenciát jelent-e. Példa:
$ cat | od -tx1
Lő<BackSpace>
<Control+D;
0000000 4c 0a    # helyes működés
0000000 4c c5 0a # hibás működés: utf8-at használunk, de a 'stty iutf8' nincs érvényben
K: És ha én egzotikus Unix-rendszert használok, ahhol nincs ilyen beállítás?
V: Az pech.
K: Off-topik lenne, ha megkérdezném, hogyan állítsam be a TZ változót?
V: Hát, ha magyar időhöz akarod állítani, akkor nem annyira; a legfontosabb, hogy ha már működik a rendszered, akkor ne piszkálj hozzá, egyébként az alábbiak közül próbáld ki valamelyiket (az elsőhöz kell a timezone adatbázis (avagy Olson-adatbázis, zoneinfo-adatbázis) a gépedre, a másodikhoz nem)
export TZ=Europe/Budapest
export TZ=CET-1CEST-2,M3.5.0/2,M10.5.0/3
K: És ha egy negyven évvel ezelőtti dátumról kellene megállapítani, hogy volt-e akkor nyári időszámítás? (Mert mondjuk a fájlrendszer UTC-ben tárolja a fájlok keletkezési idejét, de a ls-nek LT-ben (azaz helyi idő szerint) kellene kiírnia.)
V: Az első megoldással ez lehetséges, a másodikkal nem.
K: Szóval nem lehet semmi baj, ha TZ=Europe/Budapest beállítást használok?
K: Elvileg semmi, de a gyakorlatban zavart okozhatnak például azok az esetek, amikor a nyári időszámítással járó óraelőreállítást 23:00-kor vagy éppen éjfelkor tartották; az utóbbi miatt például az '1941-04-08 00:00:00' időpont nem is létezett.
Néhány példa ilyen időpontokra (ezek 'téli időszámítás' szerint értendők):
    1916-04-30 23:00:00
    1941-04-08 00:00:00
    1945-05-01 23:00:00
    1954-05-23 00:00:00
    1955-05-23 00:00:00
    1956-06-03 00:00:00
Megj: a nemlétező időpontokat egyes programok visszautasítják, mások esetleg 'jószándékúlag korrigálják'; ez végeredményben egy óraval nagyobb időpontot jelenthet, ami különösen akkor látványos, ha az óraátállítás 23:00-kor történik, amikor korrekció miatt a dátum-rész is változik (a következő napra). Ez kétszer fordult elő: 1916.04.30-án és 1945.05.01-én.
K: Ha már így eltértünk a dátumok és idők felé, azt is megkérdezem, mit tegyek, ha dátumokkal szeretnék számolni (pl napokat hozzáadni/kivonni), de csak időpontok kezelésére való eszközöket használhatok? Ha megszorzom a napok számát 24*60*60-nal, hogy másodpercet kapjak, és azzal számolgatok, nem lehet bajom a nyári/téli időszámítás miatt?
V: Hogyne lehetne! A legjobb ötletem az, hogy a kérdéses dátumot egészítsd ki 00:00:00 időponttal, és úgy számolj vele, mint egy UTC-beli időponttal, pl egy bash-scriptben:
    Now="$(date +%Y%m%d)"
    Then="$(date --utc +%Y%m%d -d "$Now UTC -28203 days")"
    echo "$Now" "$Then"
    20180626 19410408
K: X Window alatt hogy tudok saját billentyűkiosztást léterhozni?
V: Egy nagyon flexiblis, rugalmas, felhasználóbarát rendszerrel, melynek elemei pl. az xkbcomp, setxkbmap programok.
K: Ezzel azt akarod mondani, hogy nagyon bonyolult és dokumentálatlan?
V: Igen.
K: Ezzel tudom például a NumLock billentyűt letiltani?
V: Például ez a script megcseréli a NumLock és a nálunk nem létező "Kata" billentyűket:
xkbcomp $DISPLAY proba.xkb
sed -i.bak 's/<NMLK> = 77;/<NMLK> = 98;/
            s/<KATA> = 98;/<KATA> = 77;/' proba.xkb
xkbcomp proba.xkb $DISPLAY
— Adatbázisok —

K: A PHP programom adatbázist is használ (pl. MySql-t), szükségszerű-e, hogy az adatbázis ugyanazt a kódolást használja, mint a szájt egésze?
V: Egyszerűsíti a dolgokat, de nem szükségszerű, php-ban is használhatod az iconvot (kivéve, ha szolgáltatód elfelejtette belefordítani, lásd a phpinfo-t).

K: Átállítottam az adatbázisom beállításait; az azóta bekerült adatok jók, de a régiek nem konvertálódtak át automatikusan!
V: Elhiszem.
K: És mit csináljak, hogy jó legyen?
V: Ha tesztrendszerről volt szó, akkor a DELETE FROM tábla; utasítás a barátod; ha fontos adatokról, akkor az export + kézi javítás + import eljárást ajánlom.

K: Ha nem tudom biztosan, hogy mi van az adatbázisban (például, hogy ahol kérdőjelet látok, ott tényleg kérdőjel van-e, vagy megjeleníthetetlen karakter), mit tegyek?
V: A tárolt érték hexa kódját kérdezd le, azt már tudod ellenőrizni. Bővebben lásd itt.
— MySql —
K: Hol lehetne olvasni a MySql idevágó beállításairól?
V: Például itt: MySQL 5.1 Reference Manual :: 9 Internationalization and Localization A MySql szerver képes konvertálni a programod által használt karakterkészletre/-ről, főleg, ha megmondod neki, hogy mi az. Példák:
SET NAMES 'utf8mb4'
SET NAMES 'latin2'
Bővebben lásd itt: 9.1.4. Connection Character Sets and Collations
Kieg: PHP esetén itt van ugyanerre a célra a mysql(i)_set_charset is. Ezt a beállítást a lekérdezhetjük a mysql_client_encoding/mysqli_character_set_name függvénnyel.
Kieg2: Ez utóbbi az ajánlott módszer; mivel ekkor a MySql kliensoldali kódja is tudomást szerez a beállításról, nem csak a szerveroldal; ennek például a mysql(i)_real_escape_string függvény használatakor van jelentősége (egyes egzotikus kódolások esetén). Lásd még ezt a pontot.

K: Azt olvasom a php.net-en, hogy jó lenne elszakadni a mysql-től, és a mysqli felé mozdulni.
V: Szerintem kapkodni nem érdemes, de azért gondolkodj el a dolgon, ne várd meg, míg kihúzzák alólad a szőnyeget. Én személyesen legfőbb előnyének nem azt látom, hogy objektumokat lehet benne orientálni, hanem azt, hogy bind-változókat használhatunk vele.

K: A MySql világában az utf8 az ugyanaz, mint amit mindenki más UTF-8-nak nevez?
V: Nem egészen, náluk az utf8 a CESU-8-at jelenti.

K: És hogy mondják MySql nyelven azt, amit mindenki más UTF-8-nak nevez?
V: Annak pedig utf8mb4 a neve.

K: Pótkérdés: és az biztos, hogy az UTF-8-ban legfeljebb négybájtosak a kódok?
V: A korábbi szabvány (RFC2779) hatbájtos kódokat is megengedett, a későbbi (RFC3629) ezt négy bájtra csökkentette.

K: Kicsit pontosabban mit állít be a SET NAMES?
V: Alapvetően ezt a három session-specifikus rendszerváltozót:
mysql> set names utf8mb4;
mysql> show variables where variable_name in
       ('character_set_connection','character_set_client',
        'character_set_results','collation_connection');
+--------------------------+--------------------+
| Variable_name            | Value              |
+--------------------------+--------------------+
| character_set_client     | utf8mb4            |
| character_set_connection | utf8mb4            |
| character_set_results    | utf8mb4            |
| collation_connection     | utf8mb4_general_ci |
+--------------------------+--------------------+
K: Nem alapvetően számolva ez négy darab, nem pedig három.
V: Hát igen, a három charset-en kívül itt van még a collation, vagyis string-összehasonlítási mód. A 'character_set_connection' automatikusan beállítja a 'collation_connection'-t is valamilyen default értékre, ezt így lehet felülbírálni:
mysql> set names utf8mb4 collate utf8mb4_hungarian_ci;
mysql> show variables where variable_name in
       ('character_set_connection','character_set_client',
        'character_set_results','collation_connection');
+--------------------------+----------------------+
| Variable_name            | Value                |
+--------------------------+----------------------+
| character_set_client     | utf8mb4              |
| character_set_connection | utf8mb4              |
| character_set_results    | utf8mb4              |
| collation_connection     | utf8mb4_hungarian_ci |
+--------------------------+----------------------+
— Oracle —
K: Oracle-ről valamit?
V: Oracle-adatbázis esetén az Oracle kliensoldali programja végzi a koverziót a szerver és a felhasználó kódkészelete között, az előbbit értelemszerűen a szervertől tudja meg, az utóbbit a NLS_LANG környezeti változóból (Windows esetén esetleg registry-entryből), pl.:
export NLS_LANG=American_America.AL32UTF8
putenv ("NLS_LANG=Hungarian_Hungary.EE8ISO8859P2");
(Az első rész az üzenetek nyelvét, a második a területi beállításokat adja meg.)
Nem kell minden részt megadnunk, például csak a karakterkészlet beállítása:
export NLS_LANG=.EE8MSWIN1250
Megj.: Ezt a beállítást még az Oracle-connect előtt érdemes elvégezni, annál is inkább, mert (más beállításoktól eltérően) menet közben nem lehet módosítani ALTER SESSION paranccsal.
Kiegészítés: PHP esetén az oci_connect negyedik paraméterét is használhatjuk erre a célra.
Megj.: Ne felejtsük el, hogy ha 64-bites Windows-ban 32-bites Oracle-t használunk akkor a registry-ben nem a HKLM\SOFTWARE\ORACLE, hanem a HKLM\SOFTWARE\Wow6432Node\ORACLE a barátunk. (De még inkább a környezeti változó használata registry helyett.)
Érdekesség: A NLS_LANG-ot nem lehet AL16UTF16-ra állítani (illetve lehet, de nem fog működni). A magyarázat az, hogy ez a NLS_NCHAR szokásos/alapértelmezett értéke. Ez kb annyira logikus, mint hogy az ég színe nem lehet kék, hiszen a tenger színe a kék.
K: Jól tudom, hogy az Oracle-nek van egy saját CONVERT függvénye?
V: Igaz, használata: CONVERT (<mit>, <mibe> [, <miből>])
Például, ha az Sql*Plus-t használod, és ISO-8859-2 a karakterkészleted (Oracle nyelven: EE8ISO8859P2), akkor így próbálhatod ki:
SQL> select dump (convert ('árvíztűrő', 'UTF8', 'EE8ISO8859P2'), 16) 
     as hexutf8 from dual;
HEXUTF8
----------------------------------------------------
Typ=1 Len=31: c3,a1,72,76,c3,ad,7a,74,c5,b1,72,c5,91
K: Ha jól értem, a CONVERT harmadik paramétere (from-charset) opcionális: mi az alapértelmezés?
V: Az adatbázis karakterkódolása (NLS_CHARACTERSET), ezt felhasználva például egy ékezettelenítő utasítás így nézhet ki PL/SQL-ben:
    v_ektelen := convert (v_ekezetes, 'US7ASCII');
K: Jól látom, hogy az Oracle saját neveket használ a kódkészletekre?
V: Igen, továbbá egy egyedi számot is hozzárendel. Az alábbi konverziós függvények lehetnek érdekesek: NLS_CHARSET_ID, NLS_CHARSET_NAME, UTL_I18N. MAP_CHARSET. Példa:
select nls_charset_name(2000),
       nls_charset_id('ce8bs2000'),
       utl_i18n.map_charset('ee8iso8859p2',0,0)
from dual;
AL16UTF16  233  ISO-8859-2
Néhány fontos kódkészlet:
   1 us7ascii     us-ascii
  31 we8iso8859p1 iso-8859-1
  32 ee8iso8859p2 iso-8859-2
  10 we8pc850	  cp850
 150 ee8pc852	  cp852
 178 we8mswin1252 windows-1252
 170 ee8mswin1250 windows-1250
 870 al24utffss	  utf-8 (max. hárombájtos szekvenciák)
 871 utf8	  cesu-8
 872 utfe	  utf-8/ebcdic
 873 al32utf8	  utf-8
1000 utf16	  utf-16
2000 al16utf16	  utf-16be
2002 al16utf16le  utf-16le
K: Akkor most hányszor van az UTF8? (870-873 kódok)
V: A 870-es elavult (UniCode 1.1-nek megfelelő), maximum hárombájtos szekvenciák vannak benne; a 871-es igazából a CESU-8-at jelenti, ami az U+FFFF feletti kódokat 2*3 bájton ábrázolja. Új fejlesztéshez ne használd. (Megjegyzés: hasonló jelenség MySql-nél is van.) A 872-es UTFE EBCDIC-hez való; a 873-as AL32UTF8 a 'közönséges' UTF-8-nak felel meg.
K: És UTF16 is kétszer van?
V: Úgy tűnik. A kettő között vagy van különbség, vagy nincs. Említsük meg, hogy az oci.h fájlban van egy ilyen definíció:
#define OCI_UTF16ID 1000 /* UTF16 charset ID */
K: Erről jut eszembe: a NLS_LANG ez egyetlen hasznos változó lokalizáció ügyben?
V: Itt olvashatsz mindegyikról, pl. a dátum formátumának beállítása:
export NLS_DATE_FORMAT=YYYYMMDD.HH24MISS
Ezen beállítások nagy része menet közben is megváltoztatható, például magyar ABC szerinti rendezés beállítása SQL paranccsal így történhet:
alter session set nls_sort=hungarian;
A session beállításainak lekérdezése:
SQL> select * from nls_session_parameters;
PARAMETER               VALUE
----------------------- ----------------------------
NLS_LANGUAGE            AMERICAN
NLS_TERRITORY           AMERICA
NLS_SORT                BINARY
...
K: Ebben pont nem látom a karakterkészletet.
V: Azt még én sem találtam, sőt az Oracle leírásai sem mondanak semmi bíztatót. Itt van például a sys_context('USERENV','LANGUAGE'): amit visszaad, az úgy néz ki, mint a NLS_LANG tartalma (language_territory.charset), de benne a harmadik rész nem a kliensoldali karakterkódolás (hanem a szerveroldali).
K: A szerver beállításait hogyan lehet lekérdezni?
V:A NLS_DATABASE_PARAMETERS a barátunk:
SQL> select *  from nls_database_parameters;
PARAMETER                      VALUE
------------------------------ ----------------------------------------
NLS_NCHAR_CHARACTERSET         AL16UTF16
NLS_LANGUAGE                   HUNGARIAN
NLS_TERRITORY                  AMERICA
NLS_CURRENCY                   $
NLS_ISO_CURRENCY               AMERICA
NLS_NUMERIC_CHARACTERS         .,
NLS_CHARACTERSET               EE8ISO8859P2
NLS_CALENDAR                   GREGORIAN
NLS_DATE_FORMAT                DD-MON-RR
NLS_DATE_LANGUAGE              HUNGARIAN
NLS_SORT                       HUNGARIAN
NLS_TIME_FORMAT                HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT           DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT             HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT        DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY              $
NLS_COMP                       BINARY
NLS_LENGTH_SEMANTICS           BYTE
NLS_NCHAR_CONV_EXCP            FALSE
NLS_RDBMS_VERSION              10.2.0.5.0

20 rows selected.
K: Oracle esetében a string-literálokban használhatok hexa-szekvenciákat?
V: A közönséges literálokban nem, de van egy külön U' szintaxis, amivel igen (a literál NCHAR tipusú lesz), pl.:
SQL> select u'\d83c\df54\20ac' from dual;
🍔€
SQL> select dump(u'\d83c\df54\20ac',1016) from dual;
Typ=96 Len=6 CharacterSet=AL16UTF16: d8,3c,df,54,20,ac
Van továbbá egy unistr függvény is erre.
K: És mi ennek az unistr függvénynek az inverze?
V: Még nem találtam ilyet, addig is össze lehet csapni valamit házilag:
function nchar_to_unistr (p_str in nvarchar2) return varchar2 is
    v_out   varchar2(32767);
    i       pls_integer;
    v_chr   nchar;
    v_code  pls_integer;
    v_hex   varchar2(8);
begin
    v_out:= '';
    for i in 1..length(p_str) loop
        if i = 1 then v_out := 'unistr('''; end if;
        v_chr  := substr (p_str, i, 1);
        if v_chr between ' ' and '~' and v_chr not in ('''', '"', '\') then
            v_out  := v_out || v_chr;
        else
            v_code := ascii (v_chr);
            v_hex  := to_char (v_code, '0xxxx');
            v_hex  := substr (v_hex, length (v_hex)-3, 4);
            v_out  := v_out || '\' || v_hex;
        end if;
    end loop;
    if length(v_out)>0 then v_out := v_out || ''')';
    else v_out := '''';
    end if;
    return v_out;
end;
K: Az Oracle melyik függvényével tudok unikód és karakter-típus között konvertálni?
V: Úgy tűnik, NCHAR/NVARCHAR típusok estén erre is van lehetőség (legalábbis ha a NLS_NCHAR_CHARACTERSET paraméter értéke AL16UTF16)
declare
  nc nchar;
  n  pls_integer;
begin
  nc:= nchr(369);   -- várhatóan ű
  n := ascii(N'Ž'); -- várhatóan 381
end;
Megjegyzés: vegyük észre, hogy ASCII függvénynek nincs NASCII párja, hanem a paraméter típusától függ a működése, pl.:
SQL> select ascii('ű') charcode, ascii(to_nchar('ű')) ncharcode from dual;
  CHARCODE  NCHARCODE
---------- ----------
       251        369
K: Hogyan tudom ezt char és nchar közötti konverzióval kombinálni?
V: Például így:
declare
  c char;
  n pls_integer;
begin
  c:= to_char(nchr(369));   -- várhatóan ű
  n:= ascii(to_nchar('Ž')); -- várhatóan 381
end;
Megjegyzés: ha például egy CARON (U+02C7) karaktert akarunk ábrázolni, de úgy, hogy se a kliens, se a szerver karakter-beállítása ne számítson, azt így tehetjük meg:
declare
  caron char := to_char(nchr(711));
begin
  dbms_output.put_line(caron);
  dbms_output.put_line(ascii(caron));
  dbms_output.put_line(ascii(to_nchar(caron)));
end;
K: Ebben az utolsó példában az tűnt fel, hogy a második sor kimenete a szerver NLS_CHARACTERSET beállításától függően 161, 183 vagy 52103 is lehet.
V: Ez sajnos igaz, emiatt talán nem is érdemes így használni az ascii függvényt. Az 52103 például a kétbájtos UTF8-szekvencia (cb 87) számmá alakításából származik.
A harmadik sorban szereplő változat fixen az unikódot adja meg.
K: Ugorjunk most a Pro*C-re: Igaz, hogy a NLS_LANG állása befolyásolja a preccompiler működését?
V: Hogyne, például ellenőrizheti a forrásprogramot, hogy UTF-8-valid-e, ha úgy áll a NLS_LANG. Ha ezt elkerülnéd, akkor pl. ilyesmit írj a Makefile-ba:
%.c: %.pc
    NLS_LANG=american_america.EE8ISO8859P2 proc code=ansi lines=yes iname=$< ...
K: Miért nem magyarra állítjuk a nyelvet?
V: Megtehetjük, ha fordító félreértéseire vagyunk kiváncsiak a program valódi üzenetei helyett...
K: És mit tegyek, ha Windowst használok?
V: Programozáshoz?!
K: Ha jól értem, OCI-t használva mezőnként állíthatom a karakterkészletet (konverziót). Pro*C-ben is van erre mód?
V: A lehetőségek egy kicsit szűkebbek: először is, az első adatbázis-műveletnél beolvassa a NLS_LANG és NLS_NCHAR környezeti változókat, és minden kontextusban azokat használja (még akkor is, ha új CONTEXT-et hozol létre).
K: Ez miért baj?
V: Baj csak akkor lesz, ha különböző komponenseket akarunk egy executable-programba összegyúrni, és mondjuk az egyik pl. EE8ISO8859P2/AL16UTF16 kódolást szeretne, a másik meg AL32UTF8/AL32UTF8-at.
K: Mi is lenne ez a két kódolás az előző válaszban?
V: Pro*C-ben a host-változók deklarációjától függ, hogy milyen kódolás menjen a dróton, illetve milyen kódolás legyen a változóban (ez a kettő persze különbözhet, a konverziót az Oracle kliensprogramja végzi). Megpróbálom egy táblázattal szemlélteni:
változódeklaráció                  dróton                  változó tartalma
-----------------		   ------		   ---------------
varchar				   NLS_CHARACTERSET        NLS_LANG
varchar CHARACTER SET IS NCHAR_CS  NLS_NCHAR_CHARACTERSET  NLS_NCHAR
uvarchar			   NLS_NCHAR_CHARACTERSET  UTF16
Megjegyzés: ha nincs NLS_NCHAR, akkor ahelyett is NLS_LANG érvényesül; ha nincs NLS_LANG, akkor 7-bites ASCII-t kapunk.
K: Az Oracle szerveren milyen karakter-konverzió történik?
V: Csak NLS_CHARACTERSET és NLS_NCHAR_CHARACTERSET közötti konverzió, ha szükség van rá (vagyis NCHAR/NVARCHAR/NCLOB mezőt a kliens "simán" akar kapni/küldeni; vagy fordítva, sima CHAR/VARCHAR/CLOB mezőt a kliens NCHAR-osan akar kapni/küldeni).
K: És ha ezen konverzió során karakterek vesznek el?
V: Akkor karakterek vesznek el.
K: És minden más konverzió a kliensen történik?
V: Igen.
K: És ha olyan szűkített képességű kliensem van, ami nem ismeri a szerver (egzotikus) kódkészletét, akkor mit tegyek?
V: Akkor azt nem tudod használni. Szerezzél egy okosabb klienst! (Még az InstantClient-nek is van mindenféle kódolást ismerő változata.)
K: OCI esetén mi az OCI_ATTR_CHARSET_FORM és OCI_ATTR_CHARSET_ID jelentősége?
V: Az előbbi azt mondja meg, hogy milyen kódolás menjen a dróton, az utóbbi azt, hogy milyen kód van/legyen a kliensoldali változóban. Táblázatosan:
OCI_ATTR_CHARSET_FORM  dróton                  változó tartalma     alapértelmezés
---------------------  -----		       ----------------     --------------
SQLCS_IMPLICIT	       NLS_CHARACTERSET        OCI_ATTR_CHARSET_ID  NLS_LANG enviró
SQLCS_NCHAR	       NLS_NCHAR_CHARACTERSET  OCI_ATTR_CHARSET_ID  NLS_NCHAR enviró
K: Csak az ismétlés kedvéért: ha elveszítem a görög vagy cirill betűimet, akkor melyik oldal a hibás, a kliens, vagy a szerver?
V: Mindkettő lehetséges, pontosabban mondva, csak akkor használhatsz minden unikódot, ha mindkét oldal unikód-képes (tipikusan AL32UTF8 vagy AL16UTF16).
Például az alábbi kombináció biztonságosnak tűnik:
szerveren:
  NLS_CHARACTERSET=(valami)
  NLS_NCHAR_CHARACTERSET=AL16UTF16
  mezők típusa: NCHAR, NVARCHAR2, NCLOB, ...
kliensen:
  NLS_LANG=(valami)
  NLS_NCHAR=AL32UTF8
  mezők típusa:
    VARCHAR CHARACTER SET IS NCHAR_CS (Pro*C)
    OCI_ATTR_CHARSET_FORM=SQLCS_NCHAR (OCI)
K: Java-kliens (JDBC) esetén van valami különösebb aggódnivaló?
V: Például programfutáskor problémát okozhat, ha az orai18n.jar nem szerepel a classpath-on. Előfordulhat, hogy nincs hibaüzenet, "csak" hibás adatokat olvasunk ki az adatbázisból. Adott esetben elhelyezhetünk a 'main'-ben egy ilyen ellenőrzést:
if (oracle.jdbc.driver.OracleDriver.class.getClassLoader().
    getResource ("oracle/i18n/data/lx20020.glb") == null) {
    System.out.println ("Úgy érzem, hogy nincs meg az orai18n.jar -- kilépek");
    return;
}
K: JDBC-ről szólva, mi a különbség setString és setNString, illetve getString és getNString között?
V: Az előbbi esetben ettől függ, hogy a dróton NLS_CHARACTERSET vagy NLS_NCHAR_CHARACTERSET menjen-e; NCHAR-os mezők esetén az utóbbi ajánlott (az előbbi a szerver beállításától függően karaktervesztést okozhat, pl. EE8ISO8859P2-be nem férnek bele a cirill/görög betűk).
Az utóbbi esetben nem látok különbséget, ugyanis a getString/getNString akkor fut, amikor az adat már megérkezett a kliensre, ahol fixen UTF-16-ra konvertálódik.
K: JAVA/JDBC-esetén van-e valamilyen különleges szabály a NLS_LANG beállítására?
V: Ha méréseim nem csalnak, tetszés szerint beállíthatod, nem lesz hatása. Helyette a user.language és a user.country használható, vagyis azok alapján állítja be az Oracle a NLS_LANGUAGE és a NLS_TERRITORY értékét. Pl.:
java -Duser.language=hu -Duser.country=HU -Dfile.encoding=iso-8859-2 \
    -cp /opt/lib/java/ojdbc6.jar:/opt/lib/java/orai18n.jar: \
    ...
Kieg: Érdekességként megemlítem, hogy a 10.2.0.1 verziójú Oracle kliens nem boldogul a -Duser.country=hu -Duser.language=en kombinációval, de a 10.2.0.5 verzióban ez is működik.
K: Az Oracle adatbázisban mezőnként vagy táblánként tudom állítani a karakterkódolást (vö MySQL) ?
V: Adatbázisonként, mivel ezt a CREATE DATABASE parancs CHARACTER SET (és NATIONAL CHARACTER SET) záradékával tudod beállítani, és később megváltoztatni nem lehet.
K: Ha változó hosszú karakterkódolást (értsd: AL32UTF8-at) állítok be, az járhat sebesség-csökkenéssel? És lehet gondom abból, hogy az ékezetes szöveg nem fér el abban a mezőben, amiben az ékezet nélküli elfér?
V: Igen. (FixMe: ide kellene a NLS_LENGTH_SEMANTICS leírása.
— ODBC —
K: ODBC-ről tudsz valamit mondani?
V: A unixODBC + Oracle kombinációt próbáltam, azt figyeltem meg, hogy a SQL_C_CHAR típus használata esetén a kódolás az NLS_LANG-nak megfelelően alakul, a SQL_C_WCHAR esetén pedig fixen UTF-16; ebből arra következtetek, hogy ha olyan ODBC-s programot akarnánk készíteni, amelynek a működése nem függ az éppen használt adatbáziskezelőtől (és annak beállításaitól), akkor az SQL_C_WCHAR-t érdemes használni.
— PDF —
A PDF bináris fájlformátum, amiről egyelőre nincs itt sok adat, de az megnyugtató, hogy az ékezetes betűk itt is lehetnek problémásak. Adott esetben az is előfordulhat, hogy az Acrobat Reader-ben jól látszanak az őŐűŰ betűk, de a vágólapon át kimásolva már oOuU látszik.
Unixban a PDF-fájlokban használt betűtipusokat a pdffonts(1) programmal listázhatjuk, pl:
$ pdffonts test1.pdf # ebben nyugat-európai õÕûÛ betűk vannak
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
Courier-Bold                         Type 1            WinAnsi          no  no  yes      6  0

$ pdffonts test2.pdf # ebben magyar őŐűŰ betűk vannak
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
CourierNewPS-BoldMT                  TrueType          Custom           no  no  yes      7  0

$  pdffonts test3.pdf # ebben magyar betűk vannak, de a copy+paste során 'elromlanak'
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
TimesNewRomanPS-BoldMT               TrueType          Custom           no  no  no       9  0
— FPDF —
K: Mifene az az FPDF?
V: Egy PHP modul, PDF-ek előállítására szolgál. A továbbiakhoz az 1.8.6-os (vagy újabb) verziót használjuk.
K: Hogyan és hová kell telepíteni?
V: Erről nincs sok szó az install.txt-ben sem, Unixon valami ilyesmit lehetne javasolni:
mkdir -p /usr/local/share/php
cd /usr/local/share/php
tar xzf /download/fpdf186.tgz # unzip /download/fpdf186.zip
ln -s fpdf186 fpdf
chmod -R o-w fpdf/ # az alapbeallitas nem egeszen biztonsagos ('world writable')

K: És a PHP meg fogja ott találni?
V: Az a php.ini fájl beállításaitól függ, pontosabban az include_path-tól; illetve használhatod a set_include_path függvényt is.

K: No igen, és hogy lesznek az ezzel előállított PDF-ben helyes magyar ékezetek?
V: Ahhoz, hogy a SetFont-tal kiválaszthass egy fontot, kell legyen egy megfelelő fontnév.php fájl a */fpdf/font könyvtárban. A gyárilag szállított fájlok cp1252-hez (vagyis nyugat-európai betűkhöz) vannak kialakítva.

K: És honnan lesznek a cp1250-es (kelet-európai betűs) fájlok?
V: Ehhez a mellékelt makefont.php-t kell használni, és kellenek hozzá a Windows-os ttf fájlok is. Példa:
FPDF=/usr/local/share/php/fpdf # vagy ahol van
WINFONT='/C/Windows/Fonts'     # vagy ahol vannak a fontok
for FONT in arial ariali arialbd arialbi; do
    php $FPDF/makefont/makefont.php "$WINFONT/$FONT.ttf" cp1250 false
done
K: Ugyanez Windows-on hogy lenne?
V: Értelmszerűen módosítani kell a scriptet (vagyis batch-et, Windows-os szóval), valami ilyesmi lehetne:
@echo off

set FPDF=C:\PHP-EXT\FPDF
set WINFONT=C:\Windows\Fonts

cd %FPDF%\font
mkdir cp1250 2>nul:
cd cp1250
for %%I in (%WINFONT%\*.ttf) do php %FPDF%/makefont/makefont.php %%I cp1250 false
Megj: További Windows-os információkért lapozz vissza ide.
K: Ezt minden futásnál újra meg újra meg kell csinálni?
V: Nem, a fájlok újrahasznosíthatóak; több megoldás képzelhető el, az egyik ez: az fpdf font-könyvtárában készítsünk egy cp1250 nevű alkönyvtárat, és oda helyezzük el a létrehozott *.php fájlokat.
FPDF=/usr/local/share/php/fpdf	# vagy ahol van
WINFONT='/C/Windows/Fonts'	# vagy ahol vannak a fontok
cd $FPDF/font
mkdir cp1250
cd cp1250
for i in "$WINFONT"/*.ttf; do	# vagy nagybetűvel: *.TTF
    php $FPDF/makefont/makefont.php "$i" cp1250 false
done
K: És a SetFont automatikusan az új fájlokat fogja használni?
V: Nem, ehhez kell még egy AddFont is. Komplett példa:
#!/usr/local/bin/php
<?php /* fpdf-test.php encoding="iso-8859-2" */

    require_once ('fpdf/fpdf.php');

    $pdf = new FPDF();
    $pdf->AddPage();
    $pdf->AddFont('Arial','B','arialdb.php','font/cp1250');
    $pdf->SetFont('Arial','B',16);
    $pdf->Cell(40,10,'árvíztűrő tükörfúrógép');
    $pdf->Output('fpdf-test.pdf', 'F');
?>
K: Ez volt a nem-beágyazott font, ugye? Mutatnál példát a beágyazottra is?
V: Tegyük fel, hogy a csodas.ttf tartalmazza a CsodaSzep fontot (kerülném a konkrét neveket, mivel valaki más fontjának beágyazása esetleg jogsértés is lehet), ekkor valami ilyesmit tehetünk (ismétlem, a többféle lehetséges megoldás közül ez csak az egyik):
FPDF=/usr/local/share/php/fpdf # vagy ahol van
$FPDF/makefont/makefont.php csodas.ttf cp1250 true
cp csodas.php $FPDF/font/cp1250/
cp csodas.z   $FPDF/font/cp1250/
Ezután a programban ugyanúgy használhatjuk:
    $pdf->AddFont('CsodaSzep','','csodas.php','fonts/cp1250');
    $pdf->SetFont('CsodaSzep','',16);

K: Miért épp cp1250 és nem iso-8859-2?
V: A leírt módszerrel mindkettőt megcsinálhatod (külön alkönyvtárakba), nem fogják zavarni egymást (ugyanebben a FAQ-ban találsz infót arról, hogy mi a két kódkészlet között a különbség).

— TCPDF —

K: És a TCPDF is valami hasonló?
V: Igen, van hozzá leírás példákkal; részletesebb leírás magában a tcpdf.php fájlban van, kommentek formájában.

K: Hogyan telepítsem?
V: Az egyik lehetőség, hogy elolvasod a leírást, a másik, amit én alkalmaztam, hogy a letölthető .zip fájl tartalmát a /usr/local/share/php/tcpdf könyvtárba helyeztem, utána futtattam a chmod -R g-w,o-w /usr/local/share/php/tcpdf parancsot, mivel a jogbitek egy kicsit ijesztőek voltak (world-writeable fájlok).
Érdemes gondoskodni arról is, hogy a php.ini-ben az include_path tartalmazza a /usr/local/share/php -t (ennek részleteit lásd az FPDF-nél).

K: Ez ugyebár UTF-8 kompatibilis, és egy csomó beépített fontja van... Akkor ezzel nyilván nagyon könnyű magyar nyelvű PDF-et csinálni.
V: Nagyon, de ha mégis kérdőjel jelenne meg az 'ő' és 'ű' helyén egyes fontoknál; illetve ha olyan fontokat is használni akarsz, amik nincsenek benne gyárilag, akkor azért van egy kis gond. Ilyenkor egy pici programot futtatunk, amely a gépünkön meglévő 'jó-ékezetű' TTF fájlokból az AddTTFFont függvénnyel létrehozza az új/javított font-leíró fájlokat a tcpdf/fonts könyvtárban.
$ cd /tmp
$ cat >tcpdf-import.php <<DONE
#!/usr/local/bin/php
<?php /* tcpdf-import.php */

    require_once ('tcpdf/tcpdf.php');

    $pdf = new TCPDF (PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

    for ($i=1; $i<$argc; ++$i) {
	$fontname= $pdf->AddTTFFont ($argv[$i], 'TrueTypeUnicode', 'UTF-8');
	printf ("from file '%s' font '%s' created\n", $argv[$i], $fontname);
    }
    $pdf->Close ();
?>
DONE
$ su # root-ként tudjuk írni a tcpdf/fonts könyvtárat
# TCPDF='/usr/local/share/php/tcpdf' # vagy ahol van
# WINFONT='/C/WINDOWS/Fonts' # vagy ahol van
# for font in trebuch times arial; do # vagy amit jónak látunk
#     rm $TCPDF/fonts/$font*php # hajlamos nem-felülírni a meglévőt
#     php tcpdf-import.php "$WINFONT/"*.ttf
# done
# ls -ltr $TCPDF/fonts # a végén kell lássuk a szép új fájlokat
K: Egy tesztprogramot kaphatok?
V: Véletlenül épp csináltam egyet (fájlba ír):
#!/usr/local/bin/php
<?php /* tcpdf-test.php encoding="iso-8859-2" */

    require_once ('tcpdf/tcpdf.php');

    $pdf = new TCPDF (PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    $pdf->AddPage ();

    $txt= 'Árvíztűrő tükörfúrógép';
    $utxt= iconv ('ISO-8859-2', 'UTF-8', $txt); /* nem kell, ha eleve UTF-8-ban vagyunk */

    $pdf->SetFont ('times', 'BI', 20);
    $pdf->Write (0, $utxt);

    $pdf->SetFont ('trebuc', 'BI', 20);
    $pdf->Write (0, $utxt);

    $pdf->SetFont ('arial', 'BI', 20);
    $pdf->Write (0, $utxt);

    // close and write to file
    $pdf->Output ('test.pdf', 'F');
?>
— HTML2PDF —
K: Ha jól értem, a html2pdf is a TCPDF-et használja.
V: Úgy látom én is. A telepítését is ahhoz hasonlóan végeztem: unzip a /usr/local/share/php/html2pdf-be. Most jön egy érdekes lépés: a beledolgozott TCPDF-et töröljük, és helyettesítjük a saját, kijavított fontú példányunkkal:
# cd /usr/local/share/php
# ls -ld html2pdf/_tcpdf_5.0.002 tcpdf
drwxr-xr-x 8 root root 4096 May 27  2011 html2pdf/_tcpdf_5.0.002 # ezt fogjuk helyettesíteni
drwxr-xr-x 8 root root 4096 Mar  4 21:57 tcpdf			 # ezzel
# mv html2pdf/_tcpdf_5.0.002 html2pdf/orig_tcpdf_5.0.002
# ln -s ../tcpdf html2pdf/_tcpdf_5.0.002
K: És a tesztprogram?
V: Itten van; ha kipróbálod, láthatod, hogy az Arial nem jól jelenik meg, mivel azt belsőleg valamilyen lelki okból Helveticá-ra cseréli, amiben nem jó a magyar 'ű' és 'ő'.
#!/usr/local/bin/php
<?php /* tcpdf-test.php encoding="iso-8859-2" */

    $kPathUrl = 'No random notices, pls';
    require_once ('html2pdf/html2pdf.class.php');

    $content = "<page>\n".
        "<h1>Árvíztűrő tükörfúrógép</h1>\n".
        "<p style=\"font-family: times;\">Öt szép szűzlány őrült írót nyúz.</p>\n".
        "<p style=\"font-family: trebuc;\">Öt szép szűzlány őrült írót nyúz.</p>\n".
        "<p style=\"font-family: arial;\">Öt szép szűzlány őrült írót nyúz.</p>\n".
        "</page>\n";
    $ucontent= iconv ('ISO-8859-2', 'UTF-8', $content);
    /* nem kell, ha eleve UTF-8-ban vagyunk */

    $html2pdf = new HTML2PDF ('P', 'A4', 'en');
    $html2pdf->WriteHTML ($ucontent);

    $html2pdf->Output ('html2pdf-test.pdf', 'F');
?>
K: És ha mégis szeretném, hogy az Arial megmaradjon Arialnak?
V: Ezt a patch-et próbáld ki:
--- html2pdf/_class/parsingCss.class.orig       2011-05-26 18:01:10.000000000 +0200
+++ html2pdf/_class/parsingCss.class.php        2013-04-11 12:42:33.000000000 +0200
@@ -318,3 +318 @@
-            if($family=='arial')
-                $family='helvetica';
-            elseif($family=='symbol' || $family=='zapfdingbats')
+            if($family=='symbol' || $family=='zapfdingbats')
@@ -328,3 +326 @@
-        if($family=='arial')
-            $family='helvetica';
-        elseif($family=='symbol' || $family=='zapfdingbats')
+       if($family=='symbol' || $family=='zapfdingbats')
— E-mail —
K: Ha egy email fejrészében ékezetes betűk vannak, az hogyan továbbítódik?
V: Hét bites ASCII-re kódolva az RFC2047-ban leírt módszerrel. Példa magyar szövegek és ISO-8859-2 használatával:
ezt látod:
     To: Őrült Író <lzsiga@domain.hu>
Subject: Árvíztűrő tükörfúrógép
ez van mögötte:
     To: =?ISO-8859-2?Q?=D5r=FClt_=CDr=F3?= <lzsiga@domain.hu>
Subject: =?ISO-8859-2?Q?=C1rv=EDzt=FBr=F5_t=FCk=F6rf=FAr=F3g=E9p?=
K: Ez a levél törzsére is vonatkozik?
V: Nem, a levél törzse a fejrészben lévő Content-Type és Content-Transfer-Encoding értékektől függ. ISO-8859-2 használata esetén a legtisztább eset ez:
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: 8bit
Ekkor az üzenetben az ékezetes betűk úgy mennek át, ahogy megjelennek. Ennél csúnyább a következő megoldás:
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: quoted-printable
a levétörzsben ezt látod:
Kérjük tájékoztass, hogy a szolgáltatás működőképes-e.
ez van mögötte:
K=E9rj=FCk t=E1j=E9koztass, hogy a szolg=E1ltat=E1s m=FBk=F6d=F5k=E9pes-e.
Ennél már csak az csúnyább, ha a bináris fájlok átvitelére való base64-kódolást használjuk szövegekre:
Content-Type: text/plain; charset=ISO-8859-2
Content-Transfer-Encoding: base64
Ebben az esetben a tartalom (vagyis a levél "forráskódja") olvashatatlan – ez persze a hétköznapi felhasználásban nem probléma, hiszen a levelezőprogram tökéletesen eligazodik a különféle formátumok között, de ha valamiért saját programból akarjuk kezelni a levelet, fel kell készülnünk a levéltörzs különböző lehetséges formáinak kezelésére a Content-Transfer-Encoding függvényében.

K: HTML (vagy PDF/GIF/etc) formátumú levelet csináltam, tök szép is lett, de valaki (pl. a spam-szűrő), azt mondja, hogy jobb lenne, ha plain-text-ben is meglenne ugyanaz. Ez miért lenne jó?
V: Egyrészt azoknak kedvezne, akik csak szöveges formátumot olvasnak, vagy valamilyen digest-formában olvassák a levelet, esetleg nem (jól) látnak, és egy program olvassa fel nekik a leveleket; másrészt megbékítené a spamszűrőt.
K: És akkor kétszer jelenik meg a levél szövege a címzettnél?
V: Szó sincs róla, azért hívják ezt multipart/alternatives-nek, hogy jelezzék, ezek egymás alternatívái, csak az egyiket kell megjeleníteni.

K: Valamelyik levelezőprogram (most nem akarom az androidos Outlookot nevesíteni) minden ékezetes betű helyett egy ilyen szekvenciát jelenít meg: ďż˝ Mi lehet ennek az oka?
V: Az email ISO-8859-2-ben van, de a program egyik agyféltekéje UTF8-ban gondolkodik, ezért az ékezetes betűket 'hibás UTF8-szekvencia'-ként azonosítja, és lecseréli őket � -re (REPLACEMENT CHARACTER, U+FFFD, UTF8-ban EFBFBD) A program másik agyféltekéje tudja, hogy ISO-8859-2-ben kellene működni, ezért az EF,BF,BD bájtokat eszerint is jeleníti meg: U+10f,U+17c,U+2dd azaz ďż˝).
K: És ha olyan szekvenciát látok, hogy �, mire gondoljak?
V: Ez az előbbi esettel analóg, csak ISO-8859-1 kódolással: U+ef,U+bf,U+bd azaz �
K: És mi lenne a megoldás?
V: Nincs megoldás, a levél küldőjének kellene UTF8-ra áttérnie.
— SMS —
K: 7-bites, 160-karakteres 'ékezetnélküli' üzemmódban milyen ékezetes betűket használhatok?
V: Ez a wiki oldal írja le, kiemelem belőle a nekünk fontos betűket:
    SMS-kód karakter unikód/latin1
    05      é	     e9
    06      ù	     f9
    07      ì	     ec
    08      ò	     f2
    1f      É	     c9
    5b      Ä	     c4
    5c      Ö	     d6
    5e      Ü	     dc
    7b      ä	     e4
    7c      ö	     f6
    7e      ü	     fc
    7f      à	     e0 
K: 8-bites, 140-karakteres üzemmódban milyen ékezetes betűket használhatok?
V: Fogalmam sincs, nincs olyan készülékem, amivel ilyet lehetne küldeni.
K: 16-bites, 70-karakteres üzemmódban milyen ékezetes betűket használhatok?
V: Ez megfelel az UCS2-nek, tehát minden magyar betű benne van (meg minden más karakter is, aminek az unikódja elfér 16 biten... persze az nem garantált, hogy a címzett készüléke mindet meg is tudja jeleníteni).
— Samba —
K: A Samba-nak is van köze ehhez a FAQ-hoz?
V: Bizonyos értelmeben igen: az én esetemben a /etc/passwd-ben volt ékezetes magyar szöveg, latin2-es kódolással, ami megakadályozta a Samba-4.4.2 elindulását. Az egyik lehetőség a fájl utf8-asítása lett volna, a másik a smb.conf módosítása az alábbiak szerint:
unix charset = iso-8859-2
dos charset = cp852
(ebből az első sor a lényeges)
K: Ha már itt tartunk, mi a legfontosabb tudnivaló az ékezetes fájl- és könyvtárnevekkel kapcsolatban?
V: Hát az, hogy ne használjunk ilyeneket. Ugyanez vonatkozik a szóközökre és speciális jelekre. (Ha valaki azzal állna elő, hogy a fájlnévben kell az ékezet/szóköz, mert az jelenik meg a felhasználó böngészőjében, akkor magyarázzuk el neki, hogy a fájlnév egyáltalán nem arra való, hogy megjelenjen a felhasználó böngészőjében.
— RSA-kulcspár —
K: Ez a rész vajon hogy került ide?!
V: Fogalmam sincs. Lehet, hogy valaki valamit rosszul csinált.
K: Hogyan generálok RSA-kulcspárt az OpenSSL programmal?
V: Két lépésben, az első a privát kulcsot hozza létre, a második abból a publikust (látszik, hogy a kettő nem szimmetrikus, a privát több információt tartalmaz, mint a publikus)
openssl genrsa -out hugo.rsaprv.key 2048
openssl rsa -in hugo.rsaprv.key -RSAPublicKey_out -out hugo.rsapub.key
openssl rsa -in hugo.rsaprv.key -pubout -out hugo.pub.key
K: Ez nem három lépés volt egészen véletlenül?
V: Hát igen, úgy tűnik, hogy a publikus kulcsnak két formája is lehetséges; egyes programok esetleg az egyiket szeretik, mások a másikat. Maga az openssl a 'pub'-ot látszik szeretni (csak azzal működik a következő):
echo 'Malacvacsora' |\
openssl rsautl -encrypt -out titkos -pubin -inkey hugo.pub.key
openssl rsautl -decrypt -in titkos -inkey hugo.rsaprv.key
Malacvacsora
Másik példa:
openssl pkey -pubin -in hugo.rsapub.key -text
unable to load Public Key
openssl pkey -pubin -in hugo.pub.key -text
(kiírja a kulcs adattartalmát)
Megj: Tudományosan mondva az 'rsapub' PKCS#1 formában van, a 'pub' pedig PKCS#8 formában.
K: Ez a két változat egymásból is előállítható?
V: Valami ilyesmi lenne:
openssl rsa -pubin -in hugo.pub.key -RSAPublicKey_out -out test.rsapub.key
openssl rsa -RSAPublicKey_in -in hugo.rsapub.key -pubout -out test.pub.key
K: Szemmel belenézve úgy látom, hogy különbözik a szöveges fejrész, illetve a 'pub' változatban az adattartalom hosszabb, mint a 'rsapub' változatban.
V: Ez így van, sőt a hosszabb változat a rövidebbtől csak egy fejrészben különbözik, ami (legalábbis az én esetemben) az alábbi 32 bájt (base64 nélkül 24 bájt):
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
K: Ha történetesen C-programból szeretnék kulcspárt generálni, milyen függvényeket használhatok?
V: Ezeket javasolnám: RSA_generate_key, i2d_RSAPrivateKey ('prv'-hez), i2d_RSAPublicKey ('rsapub'-hoz), i2d_RSA_PUBKEY ('pub'-hoz). Az utóbbi három leírása itt olvasható.
K: Ha közben fejlődtek a verziók, akkor a fentiket parancsokat lehet "korszerűbben" is használni?
V: Például:
openssl genpkey -out demo_rsa.prvkey.pem -algorithm rsa -pkeyopt rsa_keygen_bits:2048
openssl pkey -pubout -in demo_rsa.prvkey.pem -out demo_rsa.pubkey.pem
echo 'String to hash' |\
openssl pkeyutl -encrypt -pubin -inkey demo_rsa.pubkey.pem |\
openssl pkeyutl -decrypt -inkey demo_rsa.prvkey.pem
K: Egy on-topic kérdés: az OpenSSL-t certificate-request (CSR) előállítására akarom használni (openssl -req), de nem nagyon látszik figyelembe venni a LC_CTYPE-ot, fixen ISO-8859-1-szerint értelmezi az inputot.
V: Ezt én is így látom; egy további lehetőség találtam: UTF8-at használni, és megadni az -utf8 opciót.
— Makefile —
K: Off-topik, de hátha elfér: egy Makefile-ban hogy lehet szóközökkel kavarni, különös tekintettel arra, hogy a stringeket ott nem teszük idézőjelek közé?
V: Egy szóközt tartalmazó változót lehet használni erre a célra; kicsit mesterkélt megoldás, de működik.
Az alábbi példában a 'CLASSPATH' változó értékét folytatósorok használatával adjuk meg, ami viszont szóközöket iktat be, tehát azoktól meg kell szabadulni a 'subst' függvénnyel:
CLASSPATH := \
    /itt/elso.jar:\
    /ott/masodik.jar:\
    /amott/harmadik.jar

EMPTY :=
SPACE := ${EMPTY} ${EMPTY}

CLASSPATH := $(subst ${SPACE},,${CLASSPATH})

run:	main.class
	java -cp=${CLASSPATH} main.class
— Docker —
K: A docker program paraméterezésénél illetve a Dockerfile-ban milyen karakterkódolást használhatok?
V: Nekem nem sikerült UTF-8-tól különböző kódolást használni, minden ékezetes betű helyett EF-BF-BD szekvencia lett, ami az U+FFFD kódú replacement character-t jelenti.
K: A konténerben futó programmal is lehet gond?
V: A LC_CTYPE-ot (és a többi érintett környezeti változót), a megszokott módon kell beállítani, de gondot okozhat, ha a "konténeres rendszerünkben" nincs/hiányos a locale. Debian-alapú rendszerekhez megoldási lehetőség a Dockerfile-ban:
RUN apt-get update && \
    apt-get install -y locales && \
    printf 'en_US ISO-8859-1\nen_US.UTF-8 UTF-8\nhu_HU ISO-8859-2\nhu_HU.UTF-8 UTF-8\n' >>/etc/locale.gen && \
    /usr/sbin/locale-gen
Centos esetén ilyesmit próbálhatunk:
RUN sed -i.bak 's/override_install_langs=.*$/override_install_langs=en_US,hu_HU/' /etc/yum.conf && \
    yum -y -q reinstall glibc-common
K: A docker build futása alatt jellegzetes Perl hibaüzeneteket kapok lokalizációügyben.
V: Azt javaslom, hogy a LC_CTYPE beállítását (pl.: ENV LC_CTYPE hu_HU.UTF-8) halaszd a lokalizáció telepítése utánra.
K: Ha már úgyis a telepítek a virtuális gépbe, érdemes a tzdata komponenst is telepíteni?
V: Hát valószínűleg nem árt. Ilyesmi lenne:
Debian: RUN apt-get install -y tzdata
RedHat: RUN yum install tzdata
Alpine: RUN apk --no-cache add tzdata
— Tipushibák —
K: Minden ékezets magyar betű helyett két 'furcsa karaktert' látok, mi lehet a baj?
V: Az adatod UTF8-ban van, de valamelyik program azt hiszi, hogy egybájtos kódolásban.
Kieg: Egy másik lehetőség, hogy UTF8-ban kódolt adatot tévedésből még egyszer UTF8-ra konvertáltál, így pl. az ű betűt jelentő C5B1 szekvenciából például C4B9C485 szekvencia lehetett, ami Ĺą-ként jelenhet meg.
Kieg: MySql esetén a SET NAMES maradt ki.
K: Minden ékezetes magyar betű egyformán kérdőjel (vagy valamilyen speciális jel) látszik, mi lehet a baj?
V: Az adatod egybájtos kódolásban van, de valamelyik program azt hiszi, hogy UTF8-ban (viszont annak persze hibás).
Kieg: MySql esetén a SET NAMES maradt ki.
K: Az ékezetes magyar betűk jól jelennek meg, kivéve az őŐűŰ betűket, amelyek helyett oOuU vagy õÕûÛ esetleg kérdőjelek látszanak.
V: Valamilyen beállítás iso-8859-2 kellene legyen, de ehelyett iso-8859-1 van. Hasonló párok (mindegyikben az első a jó): latin2 és latin1, windows-1250 és windows-1252, cp852 és cp850, ee8iso8859p2 és we8iso8859p1, ce8bs2000 és we8bs2000.
K: Esetleg egyéb magyarázata is lehet az előbbinek?
V: Igen, az hogy minden jól van beállítva, csak a használt font nem tartalmazza ezeket a betűket. Egyes programok ilyenkor valamilyen helyettesítő fontot használhatnak az említett a betűkhöz, így a betűk helyesen, de a környezetüktől eltérően jelennek meg, 'kirínak' a szövegből. (Persze ez más ritkább betűkkel is előfordulhat, például az eszperantó nyelv ékezetes betűivel: ĉĈĝĜĥĤĵĴŝŜŭŬ.)
K: PHP-ban olyan hibaüzenetet kapok, hogy Cannot modify header information - headers already sent by output started at… in… on line… akkor mi a gond?
V: A http_response_code, header, session_start, setcookie és hasonló függvények a HTTP-fejrészbe tartozó információkat (magyar szóval: metainformációkat) tartalmaznak, amelyeket a "közönséges" (tehát a HTTP-törzsrészbe tartozó) információk előtt kell megadni. A hibaüzenetben benne van az is, hogy hol lépett fel a hiba, és az is, hogy hol volt már korábban kimenet. Ahogy fentebb is említettük, egy szóköz vagy BOM is kimenetnek számít, úgyszintén az is, ha egy függvény esetleg hibaüzenetet ír ki.
K: Az ékezetes betűk helyén furcsa szekvenciákat látok, esetleg ezekből lehet következtetni valamire?
V: Ez is lehetséges, nézzünk egy példát, amelyben tévedésből utf8-ra konvertálunk valamit, ami már amúgy is utf8 volt:
Bemenet: őű (c591 c5b1)
konverzió        eredmény
win1252->utf8    őű (c385 e28098 c385 c2b1)
win1250->utf8    őű (c4b9 e28098 c4b9 c2b1)
iso88591->utf8   őű (c385 c291 c385 c2b1)
iso88592->utf8   Ĺ‘Ĺą (c4b9 c291 c4b9 c485)
Megjegyzés: az U+91 (PU1, UTF8-ban c291, HTML-ben &#x91;) egy nem nyomtatható vezérlőkaraker, de attól még a böngésző símán megjelenítheti helyette az U+2018 (LEFT SINGLE QUOTATION, UTF8-ban e28098, HTML-ben &#x2018;) karaktert, hogy windows1252-kompatibilis legyen.
Egy másik példa: Egy bizonyos programban az ékezetes betűk helyett 뿯½ (U+BFEF, U+00BD) szekvencia jelenik meg. A valószínű magyarázat az, hogy az előállító program Unicode Replacement Character-t (� U+0FFD, UTF8-ban EF-BF-BD) akart írni, de valamilyen furcsa hiba miatt az UTF-8 szekvenciát (négy bájtra kiegészítve egy bináris nullával) értelmezte két UTF-16LE karakternek: EF-BF-BD-00 => BFEF, 00BD
— Hibakeresés —

K: Ha kérdőjeleket vagy krixkraxokat látok a magyar ékezetes betűk helyett, hogyan debuggoljak?
V: Például mentsd le fájlba (wget), és egy hex-viewerrel ellenőrizd, hogy mi is van ott (ezen lap alján van egy táblázat, ami segíthet). És ha már a wget-et használod, a -S opciót is használd, amit már az előbb ajánlottam, hogy a HTTP-fejrészt is lássad.

K: További ötlet?
V: Próbáld megállapítni, hogy minden ékezetes betű egyformán rossz-e, vagy másképp rosszak/jók attól függően, hogy mi a forrásuk:

K: Már összevissza kapkodtam, mint majom a farkához, de bármit is állítgatok, valami mindig elromlik: vagy a html, vagy a php, vagy az adatbázisból jövő szöveg lesz rossz...
V: Akkor talán csináld sorrendben: először a konstans fájlok (html, txt, js, css...) tartalma jelenjen meg jól, azután a php-ból/cgi-ből származó tartalom, és végül az, ami az adatbázisból jön.

K: Arra gondoltam, hogy egy internetes levlistán vagy fórumon kérek segítséget. Az vajon jó lesz, hogy 'Nem mennek az ékezetek a szájtomon, segítsetek!'
V: Szinte tökéletes, de ha egészen profi akarsz lenni, akkor valahogy így fogalmazz (a változó részeket értelemszerűen behelyettesítve):
'Hosszas megfontolás után elhatároztam, hogy az <X> kódolást fogom használni, ehhez állítottam a .htaccess-t, a html.head.meta-t, a header-t, az adatbázist, és még mindig gondom van.
Tesztelésiből 'wget -S'-sel letöltöttem az oldalam, a Content-Type fejrész <jó/rossz>; az elmentett tartalomban hex-viewerrel megnézve az ékezetes betűk kódját, azok <olyanok/nem olyanok>, mint amit várok (ha nem olyanok, akkor milyenek: <XXH>-et vártam az <Ű> helyett, jött helyette <YYH>, lásd a függelékben a táblázatot).'

K: Az oldalam az X gépen jól működik, az Y gépen meg nem. Mi lehet a baj az Y géppel?
V: Nyomozd ki! Pont arról szól ez a 'Hibakeresés' rész.
K: Mindenestre az biztos, hogy az oldalam jó, hiszen az X gépen jól jelenik meg!
V: Ez tévedés, a hibás működés bizonyítja a hibát, de a hibátlan működés nem bizonyít semmit, lehetséges például, hogy a hibák semlegesítik egymást. Szóval: debuggolj!

K: Ha nem vagyok biztos abban, hogy pontosan mi van az adatbázisomban, hogyan kérdezhetem le a hexakódokat?
V: Az adatbáziskezelődtől függ, pl.:
MySql:  SELECT HEX (mezonev) FROM ...
Oracle: SELECT DUMP (mezonev, 16) FROM ...
  vagy: SELECT RAWTOHEX (mezonev) FROM ...
Pgsql:  SELECT ENCODE (mezonev, 'hex') FROM ...
MSSQL:  SELECT CAST (mezonev AS VARBINARY) FROM ...
K: PHP-ban hogyan lehet debuggolni?
V: Főleg teszt-kiíratásokkal, lásd print, printf, print_r, var_dump, illetve, ha nem látszik a kimenet (pl. Ajax esetén), akkor fájlba: error_log. Hasznos lehet a hexás kiíratás is a bin2hex függvénnyel, pl.:
    $s= $_REQUEST['input_mezo'];
    printf ("bin2hex(%s)=%s\n", $s, bin2hex ($s));

    $s= iconv ('ISO-8859-2', 'UTF-8', $s);
    printf ("utf8-ra kódolva: bin2hex(%s)=%s\n", $s, bin2hex ($s));
K: Ha kiírattam a HTML-ben, és láttam, hogy jó, akkor...?
V: Az nem feltétlenül elég, jobb lenne hexásan is megnézni. Ha mondjuk az van ott, hogy &#x151;, az a böngészőben úgy fog megjelenni, mint ő, de még sokkal jobb, ha ténylegesen az van ott, hogy ő.
K: Miért is? Hiszen úgyis csak HTML-hez kell, akkor meg mindegy, nem?
V: Nem, mert lehet, hogy holnap már adatbázisba akarod írni, és keresni akarsz benne... holnapután meg esetleg egy text-fájlt kell előállítani, ahol az &-szekvenciák nem használhatóak.
K: Hibakeresésről szólva, melyek azok a hibák, amelyeket a hagyományok szerint minden kezdő köteles újra meg újra elkövetni?
V: Itt van rögtön a warningok figyelmen kívül hagyása. Néhány példa, néhány programozási nyelvhez / fordítóhoz, amit csinálni kellene:
C/C++ fordítás gcc-vel: gcc -W -Wall -Wextra -pedantic ...
PHP script elejére: error_reporting (E_ALL | E_STRICT);
Perl futtatáshoz: perl -w script
Perl script elejére: use strict;
K: Az is ide tartozik, ha az egyes adatbázisműveletek után 'elfelejtem' a hibaellenőrzést? Vagy beteszem, de csak annyit írok ki, hogy 'baj van'?
V: Nagyon is jó, még elfáradnál! Két példa PHP/MySql-ból egy kezdős, meg egy haladós.
$stmt = mysql_query ("SELECT fields FROM table WHERE field='$valtozo'");
while ($row= mysql_fetch_row ($stmt)) ...
$sql = sprintf ("SELECT fields FROM table WHERE field='%s'",
    mysql_real_escape_string ($valtozo));
$stmt = mysql_query ($sql);
if ($stmt === FALSE) {
    printf ("<H1>scriptneve.rutinneve: MySql error %s on %s</H1>\n",
	htmlspecialchars (mysql_error (), ENT_NOQUOTES, 'ISO-8859-1'),
	htmlspecialchars ($sql, ENT_NOQUOTES, 'ISO-8859-1'));
    exit;
}
while ($row= mysql_fetch_row ($stmt)) ...
Kieg: További hasznos függvények: mysql_affected_rows – hány sort érintett a legutóbi módosítás (pl UPDATE), mysql_insert_id – ha a legutóbbi parancs INSERT volt, és abban egy AUTO_INCREMENT típusú kulcs töltődött, annak értékét adja vissza.
Kieg: Itt van Oracle-hez egy minta a hibavizsgálatra.
K: További lehetőségek?
V: Például, ha azt hajtogatod, hogy 'nem érdekelnek a részletek, csak azt szeretném, hogy jó legyen'. Telitalálat, ha bosszantani akarod a potenciális segítőket. Egy másik ilyen, hogy ha valaki javasol valamit, azt feleled: 'kipróbáltam, nem vált be'.
K: De ha tényleg nem vált be?
V: Akkor idézd be a kódot, amit próbáltál (pontosan, nem emlékezetből) és a hibaüzenetet/hibajelenséget. És ha egy mód van rá, a hibaüzenetek nyelvét állítsd angolra, mert nem a fordító félreértéseire vagyunk kiváncsiak, hanem az igazi hibaüzenetre.
K: Én aztán nagyon szívesen beidézem a programomat, mind a sokezer sort...
V: Legyél szíves előzőleg mindent kiszedni belőle, ami nem nélkülözhetetlen a probléma bemutatásához; viszont ami marad, az legyen komplett, fordítható, tesztelhető.
K: Dehát ez sok munkával járna...
V: Vagy pedig fizess meg egy programozót.
Függelék
Magyar billentyűkiosztás:
PC, 101/104 gombos:
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----------+
| íÍ0 | 1'~ | 2"ˇ | 3+^ | 4!˘ | 5%° | 6/˛ | 7=˛ | 8(˙ | 9)´ | öÖ˝ | üܨ | óÓ¸ | BkSpc    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----+--+--+--+--+-------+
| Tab    | qQ\ | wW| | eEÄ | rR  | tT  | zZ  | uU€ | iIÍ | oO  | pP  | őŐ÷ | úÚ× | Enter |
+--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----+-----+--+--+--+--+    |
| CapsLock  | aAä | sSđ | dDĐ | fF[ | gG] | hH  | jJí | kKł | lLŁ | éÉ$ | áÁß | űۤ |    |
+-----------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----+----+
| Shift        | yY> | xX# | cC& | vV@ | bB{ | nN} | mM< | ,?; | .:> | -_* | Shift       |
+--------------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-------------+
Az egyes mezőkben látható három karakter jelentése: billentyű önmagában, Shift-tel, AltGr-vel.
A 'z' és 'y' gyakran fordítva, vagyis az angol kiosztás szerint helyezkedik el.
PC, 102/105 gombos:
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----------+
| 0§  | 1'~ | 2"ˇ | 3+^ | 4!˘ | 5%° | 6/˛ | 7=˛ | 8(˙ | 9)´ | öÖ˝ | üܨ | óÓ¸ | BkSpc    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-------+
| Tab    | qQ\ | wW| | eEÄ | rR  | tT  | zZ  | uU€ | iIÍ | oO  | pP  | őŐ÷ | úÚ× | Enter |
+--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----+-----+--+--+--+--+    |
| CapsLock  | aAä | sSđ | dDĐ | fF[ | gG] | hH  | jJí | kKł | lLŁ | éÉ$ | áÁß | űۤ |    |
+--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----+----+
| Shift  | íÍ< | yY> | xX# | cC& | vV@ | bB{ | nN} | mM< | ,?; | .:> | -_* | Shift       |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-------------+
Függelék
A magyar betűk kódja néhány kódkészletben:
+------+----------+----------+--------------+--------------+
| Betű |    852   |  Latin2  |   Unicode    |     UTF-8    |
+------+----------+----------+--------------+--------------+
| á  Á |  A0  B5  |  E1  C1  |    E1    C1  |  C3A1  C381  |
| é  É |  82  90  |  E9  C9  |    E9    C9  |  C3A9  C389  |
| í  Í |  A1  D6  |  ED  CD  |    ED    CD  |  C3AD  C38D  |
| ó  Ó |  A2  E0  |  F3  D3  |    F3    D3  |  C3B3  C393  |
| ö  Ö |  94  99  |  F6  D6  |    F6    D6  |  C3B6  C396  |
| ő  Ő |  8B  8A  |  F5  D5  |  0151  0150  |  C591  C590  |
| ú  Ú |  A3  E9  |  FA  DA  |    FA    DA  |  C3BA  C39A  |
| ü  Ü |  81  9A  |  FC  DC  |    FC    DC  |  C3BC  C39C  |
| ű  Ű |  FB  EB  |  FB  DB  |  0171  0170  |  C5B1  C5B0  |
| ä  Ä |  84  8E  |  E4  C4  |    E4    C4  |  C3A4  C384  |
+------+----------+----------+--------------+--------------+

Kiegészítés: Egy nem-magyar betű:

+------+----------+----------+--------------+--------------+
| Betű |    852   |  Latin2  |   Unicode    |     UTF-8    |
+------+----------+----------+--------------+--------------+
| ô  Ô |  93  E2  |  F4  D4  |    F4    D4  |  C3B4  C394  |
+------+----------+----------+--------------+--------------+

Kiegészítés: Még két nem-magyar betű:

+------+----------+----------+--------------+--------------+
| Betű |    850   |  Latin1  |   Unicode    |     UTF-8    |
+------+----------+----------+--------------+--------------+
| õ  Õ |  E4  E5  |  F5  D5  |    F5   D5   |  C3B5  C395  |
| û  Û |  96  EA  |  FB  DB  |    FB   DB   |  C3BB  C39B  |
+------+----------+----------+--------------+--------------+
További olvasmányok
Off-topik, de hasznos olvasmányok